day02 【接口、多态】
今日内容介绍
接口
多态
综合练习
第一章 接口
1.1 接口的概念【重点】
1.概念:
对外暴露的规则/规范/标准,只要符合该规则/规范/标准的东西都可以使用
2.接口,是Java语言中一种引用类型,也是.java结尾的,编译后也有对应的class文件,是方法的汇总
3.作用: 实现对类的功能的扩展,解决java中类的单继承的局限性。
1.3 接口的定义格式【重点】
在最初设计理念里面,接口里面只能有抽象的方法,它就是一个抽象方法的集合。
所以它没有构造方法,不能进行实例化。
因为抽象方法,所以只有方法的定义格式(声明),没有实现。
如果想要用,我们需要写一个类去实现接口。
定义接口的格式
public interface 接口名称{
//jdk7 的时候 抽象方法
}
怎么实现呢?
public class 实现类名 implements 接口名{
//必须要重写抽象方法
}
public abstract class 实现类名 implements 接口名{
}
1.4 接口中抽象方法的定义格式和使用【重点】
接口的定义
package com.itheima.interface01;
/*
接口中
最初设计的时候要求
里面的方法是抽象的方法
格式:
public abstract 返回值类型 方法名();
特点
只有抽象方法,没有任何实现。
相当于定义了规则
由具体的实现类实现这些功能。
设计的好处
我这里定义了规范,实现类哪里完成具体的实现。
解耦!!把方法的声明与方法的实现进行拆分。
符合我们社会的规则,
好比电脑上的usb接口,定义很多规则,传输协议。
只要我们的 usb设备符合该规则就可以进行连接。
*/
public interface MyInterface {
public abstract void method();
public abstract void method2();
}
接口的实现
package com.itheima.interface01;
//使用一个具体的类 实现了接口 其实是实现接口的抽象方法
public class MyClassImpl implements MyInterface {
@Override
public void method() {
System.out.println("我重写后的method");
}
@Override
public void method2() {
System.out.println("我重写后的method2");
}
}
测试:
package com.itheima.interface01;
public class Demo {
public static void main(String[] args) {
MyClassImpl myClass = new MyClassImpl();
myClass.method();//调用的是重写后的方法
myClass.method2();//调用的是重写后的方法
}
}
1.5 完成一个 USB 接口案例
usb 接口
package com.itheima.interface02;
public interface USB {
//usb设备具备连接电脑的功能
public abstract void link();
//usb设备具备 传输的功能
public abstract void transfer();
}
键盘类
package com.itheima.interface02;
//想要连接电脑 必须 进行实现usb接口
public class KeyBoard implements USB{
public void daZi(){
System.out.println("键盘具备打字的功能");
}
@Override
public void link() {
System.out.println("键盘连接电脑了");
}
@Override
public void transfer() {
System.out.println("键盘传输 键的信号 ");
}
}
测试类
package com.itheima.interface02;
public class Demo {
public static void main(String[] args) {
KeyBoard keyBoard = new KeyBoard();
//连接电脑
keyBoard.link();
//打字
keyBoard.daZi();
// 传输信号
keyBoard.transfer();
}
}
1.6 接口里面有什么(jdk8 之前的 jdk7)重点
有常量
public interface 接口{
//成员变量--常量 一旦定义不能更改
//public static final int num;//错误的,因为你是常量,所以定义的时候必须完成赋值。
public static final int num=1;//正确的
int num2 = 2;//正确的 因为 你不写修饰符 默认修饰符 public static final 让变量变常量。
}
例子
package com.itheima.interface03;
public interface MyInterface {
public static final int num = 1;//这是完整的定义格式
int num2 = 2;//这是省略格式 说明有默认的修饰符会加上
}
package com.itheima.interface03;
public class Demo {
public static void main(String[] args) {
System.out.println(MyInterface.num);
System.out.println(MyInterface.num2);
// MyInterface.num=11;报错因为常量只能赋值一次
}
}
还有抽象方法
package com.itheima.interface03;
public interface MyInterface {
public static final int num = 1;//这是完整的定义格式
int num2 = 2;//这是省略格式 说明有默认的修饰符会加上
//抽象方法 完整写法
public abstract void show();
// 你不写 修饰符 有默认的修饰符 public abstract
void show2();
}
1.7 JDK1.8(JDK8)接口的新特性【了解】
为了提升接口的扩展性,降低维护性,所以允许了定义带有方法体的方法
1.7.1 允许 默认方法的存在
格式 public default 返回值类型 方法名(...){
方法体
}
作用:解决接口升级问题
特点:
* 子类可以不用重写默认方法,一样可以使用
演示代码
接口
package com.itheima.interface04;
public interface MyInterface {
//jdk8之后允许 接口中定义带有方法体的方法 但是需要使用 default修饰
public default void show(){
System.out.println("我是一个默认的方法");
}
}
实现类
package com.itheima.interface04;
//默认方法子类可以重写 可以不重写
public class MyClassImpl implements MyInterface {
}
测试
package com.itheima.interface04;
public class Demo {
public static void main(String[] args) {
MyClassImpl myClass = new MyClassImpl();
myClass.show();
}
}
1.7.2 JDK8 之后 接口中允许出现静态方法
作用:接口可以直接调用静态方法
格式:
public static 返回值类型 方法名(){
方法体
}
使用
接口名.方法名(); 方便 这个方法只属于接口
1.8 JDK9 新特性 (了解)
允许私有方法出现:目的是方便自己调用,不让别人调用
第二章 接口和类的关系
2.1 接口和类之间的三种关系 (重点是看源码的时候用)
类和类之间
继承关系,java 中类支持单继承,不支持多继承,支持多层继承。
类和接口之间
实现关系,类实现接口,可以单实现,可以多实现。
接口和接口之间
继承关系,可以单继承,可以多继承,也能多层继承。
查看源码
javapublic class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable 在继承一个类的基础上又实现多个接口!!
举例子: 在继承一个类的基础上 实现多个接口。
package com.itheima.interface05;
public interface MaYun {
void taobao();
}
package com.itheima.interface05;
public interface WangJianLin {
void wanda();
}
package com.itheima.interface05;
public interface LiuQiangDong {
void jd();
}
package com.itheima.interface05;
public class XinBaDie {
public void zhongdi(){
System.out.println("种地种的老棒了~~");
}
}
package com.itheima.interface05;
public class XinBa extends XinBaDie implements MaYun,LiuQiangDong,WangJianLin{
@Override
public void taobao() {
System.out.println("在淘宝开店");
}
@Override
public void jd() {
System.out.println("在京东开店");
}
@Override
public void wanda() {
System.out.println("在万达开店");
}
}
package com.itheima.interface05;
public class Demo {
public static void main(String[] args) {
XinBa xb = new XinBa();
xb.taobao();
xb.jd();
xb.wanda();
//如果凉凉 回家种地
xb.zhongdi();
}
}
2.1 抽象类和接口的区别
抽象类,可以有抽象方法,可以具体方法。
实现部分功能,避免子类重复书写,有些需要子类必须重写,设置抽象方法,让子类必须重写。
提高代码的复用性。
接口,只能有抽象方法,没有具体的方法。
实现该接口的类必须重写方法。
提高代码的扩展性,可以进行多实现,实现多个接口可以!!
在设计层面,抽象类是继承体系中的共性功能。接口是继承体系中的扩展功能。
成员上说
接口中变量变成了常量,不能更改。抽象方法。(新特性 默认 静态 私有)
抽象类中的变量还是变量。抽象方法,非抽象方法.
关系去说
- 类与类 继承关系 支持单继承 不能多继承,可以多层继承。
- 类与接口 实现关系 类实现接口 可以单实现,可以多实现。
- 接口和接口 继承关系 支持单继承,也支持多继承。
设计理念
- 抽象类 共性功能抽取
- 接口 扩展性功能抽取
第三章 多态
3.1 概念
自然界,事物的多种形态称为多态。
在 java 中,同一对象,在不同时刻表现出来的不同状态。
多态的前提
- 有继承或者是实现关系。
- 一般有方法的重写。
- 父类引用指向了子类对象
举例
Animal
package com.itheima.duotai01;
/*
定义动物类 抽象类
*/
public abstract class Animal {
//动物叫 每种叫的不一样 是一个抽象方法
public void shout(){
System.out.println("动物都会叫");
}
}
Lv
package com.itheima.duotai01;
public class Lv extends Animal {
@Override
public void shout() {
System.out.println("嗷~~~┗|`O′|┛ 嗷~~~");
}
// 驴会 拉磨
public void lamo(){
System.out.println("驴转圈拉磨");
}
}
多态测试
package com.itheima.duotai01;
public class Demo {
public static void main(String[] args) {
// Lv lv = new Lv();//原本样子即可以叫 又可以拉磨
// lv.shout();
// lv.lamo();
//多态形态 父类引用指向子类对象
Animal animal = new Lv();
//表象是 一只动物
// 本质 一头驴
animal.shout();
// animal.lamo();
// 使用多态 就只能使用父类中声明过的方法 无法使用子类特有的功能
// 调用叫的方法 会输出什么到控制台
}
}
结论:
在多态的情况下,
只能调用父类声明过的方法,因为表象是父类类型。
运行的时候执行的方法是子类的,为什么?
因为 本质是子类对象,子类重写了父类的方法,形成了覆盖。所以调用执行的是子类的方法。
3.2 多态中成员的访问特点
代码是为了推出结论
package com.itheima.duotai02;
public class Fu {
// 父类中定义一个叫做num的成员变量
int num = 100;
public void show(){
System.out.println("我是 父 show");
}
}
package com.itheima.duotai02;
public class Zi extends Fu {
//子类中定义名字叫num的成员变量
int num = 300;
//子类中定义名字叫num2的成员变量
int num2 = 200;
// 重写了父类的show方法
@Override
public void show() {
System.out.println("我是 子 show");
}
// 子类特有的方法
public void method(){
System.out.println("我是子类特有功能");
}
}
package com.itheima.duotai02;
public class Demo {
public static void main(String[] args) {
// 多态形式 父类引用指向子类对象
Fu fu = new Zi();//表象是父 真实对象是子
//编译阶段看表象 编译阶段看左边
// System.out.println((fu.num2);
System.out.println(fu.num);
fu.show();//编译不报错 因为父类中有该方法定义
// fu.method();编译报错 因为父类中没有该方法
// 你来猜一猜 运行的结果是什么 ?
// 是100和 子show
// 方法为啥是子show 因为本质对象是 zi 子已经重写了show方法。
// 变量结果为什么是100 !!! 因为变量不存在重写!!
}
}
编译阶段,永远看左边,以左边的类型为主去检查编译的语法。有错误就爆红。
运行阶段,变量看左边,方法看右边。
3.3 多态 的好处和弊端 (代码可以不敲 因为目的是感受扩展性)
多态好处案例(理解至上)
Animal
package com.itheima.duotai03;
//父类 抽象父类
public abstract class Animal {
public abstract void eat();
public abstract void sleep();
}
Cat
package com.itheima.duotai03;
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃小鱼干");
}
@Override
public void sleep() {
System.out.println("猫蜷着睡");
}
}
Dog
package com.itheima.duotai03;
public class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗啃骨头");
}
@Override
public void sleep() {
System.out.println("狗趴着睡");
}
}
Tiger
package com.itheima.duotai03;
public class Tiger extends Animal {
@Override
public void eat() {
System.out.println("老虎吃肉");
}
@Override
public void sleep() {
System.out.println("老虎蹲着睡");
}
}
AinmalShop
package com.itheima.duotai03;
public class AnimalShop {
public Animal getAnimal(int type){
if(type==1){
return new Dog();
}else if(type==2){
return new Tiger();
}else{
return new Cat();
}
}
}
Home
package com.itheima.duotai03;
public class Home {
public static void main(String[] args) {
//我们家里想养小猫小狗
AnimalShop animalShop = new AnimalShop();
Animal animal1 = animalShop.getAnimal(3);
Animal animal2 = animalShop.getAnimal(1);
feedAnimal(animal1);
feedAnimal(animal2);
}
public static void feedAnimal(Animal animal){
animal.eat();
animal.sleep();
}
// public static void feedCat(Cat cat){
// cat.eat();
// cat.sleep();
// }
//
// public static void feedDog(Dog dog){
// dog.eat();
// dog.sleep();
// }
//
// public static void feedTiger(Tiger tiger){
// tiger.eat();
// tiger.sleep();
// }
}
通过案例 我们发现 有了多态这种特征,
我们多态好处 提升了复用性,扩展性。
一个顶 N 个!!
弊端 子类无法使用 特有的功能。
怎么解决弊端 通过向下转型。
子类类型 对象名=(子类类型)父类引用;
如果不进行类型的判断 容易出现 类型转换异常
如何避免这个异常出现呢
在转型之前 进行一个类型的判断
语法如下
对象名 instanceof 类名 判断该对象是不是该类型。
package com.itheima.duotai04;
public class Demo {
public static void main(String[] args) {
//多态形式 玩
//养了一只动物
Animal animal = new Cat();//向上转型 小转成大的
animal.eat();
animal.sleep();
//想要小猫玩毛线
// animal.playMaoXian();
//因为编译不通过
// 想要调用 就要进行 向下转型!!---类似于强转
// Cat cat = (Cat)animal;
// cat.playMaoXian();
//
// Dog dog = (Dog)animal;
// // ClassCastException: com.itheima.duotai04.Cat cannot be cast to com.itheima.duotai04.Dog
// // 类型转换异常 本质猫对象不能转换成狗对象
// dog.lookDoor();
// 能不能在 转换之前 先判断能不能转换 能就转换 不能就不转换
// 先判断 多态形势下的 animal 本质是什么 是猫可以转换成猫 是狗可以转换成狗
// 判断的语法用到一个运算符 instanceof
// 变量 instanceof 类名 判断 该变量是不是该类的 对象
if(animal instanceof Cat){//判断 animal 本质是不是猫
Cat cat = (Cat)animal;
cat.playMaoXian();
}
if(animal instanceof Dog){//判断 animal 本质是不是狗
Dog dog = (Dog)animal;
dog.lookDoor();
}
}
}
3.4 通过坑爹案例 使用多态语法
LiGang
package com.itheima.kengdie;
// 李刚是一个老师 教 java基础
public class LiGang {
int age = 40;//年龄
public void teach(){
System.out.println("教java基础");
}
public void fishing(){
System.out.println("工作之余去钓鱼");
}
}
LiTianYi
package com.itheima.kengdie;
public class LiTianYi extends LiGang {
int age = 20;
public void teach(){
System.out.println("教你 连连看");
}
public void play(){
System.out.println("玩 王者农药!");
}
}
Demo
package com.itheima.kengdie;
public class Demo {
public static void main(String[] args) {
// 风和日丽 李刚带着小米同学 去钓鱼 家里只有了litianyi
// Litianyi 打游戏 打不过别人 别人有皮肤 符文 为啥没有 没钱
// 姚明 --学技术 找李刚 打电话 李天一在家接到电话 给你10W块钱 干
// 不在 怎么办
// litainyi装爹
LiGang lg = new LiTianYi();//向上转型 多态形式 带上帽子 带上胡子 带上眼镜 穿上父亲的衣服 画画鱼尾纹抬头纹
// 去姚明家 教java
System.out.println("看一下年龄:"+lg.age);//成员变量运行看左边
System.out.println("写代码需要指法 需要灵活使用鼠标 所以先教你做连连看 锻炼你的思维能力");
lg.teach();//他不会java 会 连连看
// 方法的运行看右边
System.out.println("今天先教到这里,准备回家");
// 想玩游戏
// lg.play(); 现在是李刚的状态 没有玩游戏功能
// 李天一 脱去伪装
// 向下转型
if(lg instanceof LiTianYi){
LiTianYi liTianYi = (LiTianYi)lg;
liTianYi.play();
}
}
}
第四章 综合案例
4.1 笔记本案例
需求
实现分析
相关类分析
参考代码:
代码实现
USB 接口
package com.itheima.noteboot;
/*
usb的规则
接口
里面 功能是抽象的 不给具体的实现
*/
public interface USB {
void open();//开启功能
void close();//关闭功能
}
键盘类
package com.itheima.noteboot;
// 键盘实现 USB规则
public class KeyBoard implements USB {
@Override
public void open() {
System.out.println("键盘开启");
}
@Override
public void close() {
System.out.println("键盘关闭");
}
}
鼠标类
package com.itheima.noteboot;
// 键盘实现 USB规则
public class Mouse implements USB {
@Override
public void open() {
System.out.println("鼠标开启");
}
@Override
public void close() {
System.out.println("鼠标关闭");
}
}
笔记本类
package com.itheima.noteboot;
//定义笔记本类
public class NoteBook {
// 运行功能
public void run(){
System.out.println("笔记本开始运行了...");
}
//使用usb设备功能
/**
* 定义方法的口诀
* 确定返回值
* 不需要
* 确定参数列表
* 需要 用USB设备 具体什么 不清楚 可能是鼠标 可能是键盘 那咋办?
* 只要设备符合 USB规则就可以
* 参数类型 写 接口类型!!!
*/
public void useUSB(USB usb){//方法的参数是一个 接口类型 接口类型有对象吗?本身没有,但是可以接收子类类型对象
usb.open();
usb.close();
}
//关机
public void shutDown(){
System.out.println("笔记本关机了.....");
}
}
Demo
package com.itheima.noteboot;
public class Demo {
public static void main(String[] args) {
//创建笔记本对象
NoteBook noteBook = new NoteBook();
//能不能运行
noteBook.run();
//能不能搞一个鼠标过来
Mouse mouse = new Mouse();
//能不能搞一个键盘过来
KeyBoard keyBoard = new KeyBoard();
// 笔记本能不能用一下鼠标?
noteBook.useUSB(mouse);//参数是USB接口类型
//我可以传递 子类对象 调用过程中出现了多态
//能不能用键盘
noteBook.useUSB(keyBoard);
//关机
noteBook.shutDown();
}
}