四、多态性
4.1、概述
面向对象三大特征:封装性、继承性、多态性。
extends继承或者implements实现,是多态性的前提。
4.2、多态的格式与使用
代码当中体现多态性,其实就是一句话: 父类引用指向子类对象。
格式:
父类名称 对象名 = new 子类名称();
或者:
接口名称 对象名 = new 实现类名称();
4.2、多态中成员变量的访问特点
访问成员变量的两种方式:
① 直接通过对象名称访问成员变量:
看等号左边是谁,优先用谁,没有则向上找
② 间接通过成员方法访问:
看该方法属于谁,优先用谁,没有则向上找。
4.3、多态中成员方法的访问规则
在多态的代码当中,成员方法的访问规则是:
看new的是谁,就优先用谁,没有则向上找。
口诀 :
编译看左边,运行看右边。
对比一下:
成员变量: 编译看左边,运行还看左边。
成员方法: 编译者左边,运行看右边。
4.4、多态的好处
4.5、对象的向上向下转型
● 向上转型
对象的向上转型,其实就足多态写法。
格式:
父类名称 对象名 = new 子类名称();
含义:
右侧创建一个子类对象,把它当做父类来看待使用。
注意事项:
向上转型一定是安全的,从小范围转向了大范围。
弊端:
对象一旦向上转型为父类,那么就无法调用子类原本特有的内容。
● 向下转型
对象的向下转型,其实是一个【还原】的动作。
格式:
子类名称 对象名 = (子类名称) 父类对象;
含义:
将父类对象,【还原】成为本来的子类对象。
注意事项: .
① 必须保证对象本来创建的时候,就是猫,才能向下转型成为猫。
② 如果对象创建的时候本来不是描,现在非要向下转型成为猫,就会报惜。
③ 错误写法,编译不会报错,但是运行会出现异常: java. Lang. ClassCastException
4.6、instanceof关键字判断
确定一个父类引用的对象,本来是什么子类
格式:
对象 instanceof 类型
这将会得到一个boolean值结果,也就是判断前面的对象能不能当做后面类型的实例。
4.7、案例
4.7.1、笔记本电脑
笔记本电脑(laptop) 通常具备使用USB设备的功能。在生产时,笔记本都预留了可以插入USB设备的USB接口。
但具体是什么USB设备,笔记本厂商并不关心,只要符合USB规格的设备都可以。
定义USB接口,具备最基本的开启功能和关闭功能。鼠标和犍盘要想能在电脑上使用,那么鼠标和键盘也必须遵守。
USB规范,实现USB接口,否则鼠标和键盘的生产出来也无法使用。
4.7.2、案例分析
进行描述笔记本类,实现笔记本使用USB鼠标、USB键盘
● USB接口,包含打开设备功能、关闭设备功能。
● 笔记本类,包含开机功能、关机功能、使用USB设备功能。
● 鼠标类,要实现USB接口,并具备点击的方法。
● 键盘类,要实现USB接口,具备敲击的方法。
4.7.3、案例实现
4.7、final关键字
4.7.1、概述
final关键字代表最终、不可改变的。
常见四种用法:
① 可以用来修饰一个类。
② 可以用来修饰一个方法。
③ 可以用来修饰一个局部变量。
④ 可以用来修饰一个成员变量。
4.7.2、修饰类
格式:
public final class 类名称{
...
}
含义:
当前这个类不能有任何的子类。(太监类)
注意事项:
一个类如果是final的,那么其中所有的成员方法都无法进行覆盖重写(因为没子类)
4.7.3、修饰方法
当final关键字用来修饰一个方法的时候,这个方法就是最终方法,也就是不能被覆盖重写。
格式:
修饰符 final 返回值类型 方法名称(参数列表) {
...
}
注意事项:
对于类、方法来说,abstract关键字(必须覆盖重写)和final关健字 (不能覆盖重写)不能同时使用,因为矛盾。
4.7.4、修饰局部变量
一旦使用final用来修饰局部变量,那么这个变量就不能进行更改。“一次赋值,终生不变”
备注:
对于基本类型来说,不可变说的是变量当中的数据不可改变。
对于引用类型来说,不可变说的是变量当中的地址值不可改变,地址所指向的东西 里的值可以变。
4.7.5、修饰成员变量
对于成员变量来说,如果使用final关键宇修饰,那么这个变量也照样是不可变。
注意:
① 由于成员变量具有默认值,所以用了final之后必须手动赋值,不会再给默认值了。
② 对于final的成员变量,要么使用直接赋值,要么通过构造方法赋值。二者选其一。
③ 必须保证类当中所有重载的构造方法,都最终会对final的成员变量进行赋值。
4.8、四种权限修饰符
Java中有四种权限修饰符:
自己,邻居,儿子,陌生人
注意事项:
(default)并不是关键字“default”, 而是根本不写。
4.9、内部类
4.9.1、概念
如果一个事物的内部包含另一个事物,那么这就是一个类内部包含另一个类。
例如:
身体和心脏的关系、汽车和发动机的关系。
分类:
① 成员(方法外)内部类
② 局部(方法里)内部类(包含匿名内部类)
4.9.2、成员内部类
格式:
修饰符 class 外部类名称{
//....
修饰符 class 内部类名称 {
//....
}
}
注意事项:
内用外,随意访问。
外用内,需要内部类对象。
使用:
间接使用:在外部类的方法当中,使用内部类:然后main只是调用外 部类的方法。
直接使用,公式:
外部类名称.内部类名称对象名 = new 外部类名称().new 内部类名称();
同名变量访问:
如果出现了重名现象,那么格式是:
外部类名称. **this**.外部类成员变量名
4.9.3、局部内部类(包含匿名内部类)
如果一个类是定义在一个方法内部的,那么这就是一个局部内部类。
“局部”只有当前所属的方法才能使用它,出了这个方法外面就不能用了。
格式:
修饰符 class 外部类名称 {
修饰符 返回值 类型 外部类方法名称(参数列表) {
class 局部内部类名称 {
//
}
}
}
final问题:
局部内部类,如果希望访间所在方法的局部变量.那么这个局部交量必须是【有效 “final”的】。
备注:
从Java 8+开始,只要局部变量事实不变,那么final关键字可以省略。
原因:
① new出来的对象在堆内存当中。
② 局部变量是跟着方法走的,在栈内存当中。
③ 方法运行结束之后,立刻出栈,局部变量就会立刻消失。
④ 但是new出来的对象会在堆当中持续存在,直到垃圾回收消失。
4.9.4、匿名内部类!
如果接口的实现类(或者是父类的子类)只需要使用唯一的一-次,
那么这种情况下就可以省略掉该类的定义,而改为使用**【匿名内部类】**。
格式:
接口名称 对象名 = new 接口名称() {
//覆盖重写所有抽象方法
};
对格式“new 接口名称(){…}”进行解析:
① new代表创建对象的动作。
② 接口名称就是壁名内部类需要实现哪个接口。
③ {… }这才是匿名内部类的内容。
注意事项:
① 匿名内部类,在【创建对象】]的时候,只能使用唯一次。如果希望多次创建 对象,而且类的内容一样的话, 那么就必须使用单独定义的实现类了。
② 匿名对象,在【调用方法】的时候,只能调用唯一一 次。如果希望同一个对 象,调用多次方法,那么必须给对象起个名字。
③ 匿名内部类是省略了【实现类/子类名称】,但是匿名对象是省略了【对象名 称】。
强调:匿名内部类和匿名对象不是一回事!
4.9.5、总结
定义一个个类的时候,权限修饰符规则:
外部类:public / default
成员内部类:public / protected / (default)/ private
局部内部类:什么都不能写。