多态
定义和作用
多态是在继承实现情况下的一种现象,表现为:对象多态,行为多态
一个对象表现出来的多种形态,一个对象可以是本类类型,也可以是父类类型
Animal dog = new Dog();
父类引用指向子类对象。
**作用:**多态机制可以在不修改父类代码的基础上,允许多个子类进行功能的扩展。
实现多态的前提
- 有继承关系(实现关系)
- 一般有方法重写
- 父类引用指向子类对象(接口引用指向实现类对象)
多态的优缺点
优点:
可以提高代码的扩展性和可维护性
使用父类类型的变量作为方法的形参,可以接收一切子类对象
缺点:无法使用子类特有的成员
instanceof运算符 //判断当前对象的真实类型
解决方案:
1、不要多态
2、调用特有成员的时候使用多态的向下转型
多态下成员访问的特点
-
一个对象的编译类型与运行类型可以不一致;
-
编译类型在定义对象时就确定了,不能改变,而运行类型却是可以变化的;
-
编译类型取决于定义对象时 =号的左边,运行类型取决于 =号的右边。
所以我们在使用多态方式调用方法时,首先会检查父类中是否有该方法,如果没有,则会产生编译错误;如果有,再去调用子类中的同名方法。即编译时取决于父类,运行时取决于子类。
成员变量:编译看左边,运行也看左边
编译的时候看左边的父类中是否有该成员变量,如果有则编译通过,否则编译失败
运行的时候使用的是左边父类中的该成员变量
(注意:因为是父类的引用,所以数据的访问就有局限性,只能访问到堆内存中super空间中的数据)
成员方法
静态方法:编译看左边,运行也看左边
非静态方法:编译看左边,运行看右边
总结:编译都看左边,运行除了非静态方法之外也都看左边
当父类引用指向子类对象时,父类只能调用执行那些在父类中声明、被子类覆盖的子类方法,而不能执行子类独有的成员方法。
当子类和父类有相同属性时,父类会调用自己的属性。
在进行向上转型时,父类引用调用同名的静态方法时,执行的是父类中的方法。这是因为在运行时,虚拟机已经确定了static方法属于哪个类。“方法重写”只适用于实例方法,对静态方法无效。静态方法,只能被隐藏、重载、继承,但不会被重写。
强制类型转换
- 自动类型转换:父类 变量名 = new 子类();
- 强制类型转换:子类 变量名 = (子类)父类变量
强制类型转换注意事项
- 存在继承/实现关系就可以在编译阶段进行强制类型转换,编译阶段不会报错、
- 运行时,如果发现对象的真是类型与强制转换后的类型不同,就会报类型转换异常(ClassCsatException)的错误
- 建议强转前使用instanceof关键字,判断当前对象的真实类型,再进行强转
总结:
- 多态指的是不同子类型的对象,对同一行为作出的不同响应;
- 实现多态要满足继承、重写、向上转型的条件;
- 多态分为编译时多态和运行时多态,我们常说的多态是指运行时多态;
- 方法重载是编译时多态,方法重写是运行时多态,但重写有例外情况;
- 父类引用指向子类对象时,调用的实例方法是子类重写的方法,父类引用不能调用子类新增的方法和子类特有属性;
- 父类引用指向子类对象时,父类引用只会调用父类自己的属性和static方法,不会调用子类的;
- 多态使得代码更加灵活,方便了代码扩展。