多态
同一个引用类型,使用不同的实例而执行不同操作,即父类引用指向子类对象
文章目录
1.多态的必要条件
- 一定要有继承关系
- 一定要有重写
- 父类引用指向子类对象
2.访问多态成员的特点
-
成员变量:编译时期看左边类型,运行时期看左边类型。(多态运用于行为,不是属性,所以和变量无关)
-
成员方法:编译时期看左边类型,运行时期看右边类型。(虽然运行时期看右边类型,但因为子类方法通过父类方法重写的,所以父类方法不能删除【一定要有重写】)
-
静态成员:编译时期看左边类型,运行时期看左边类型
//static是不能继承的 //所以Fu和Zi的method()是两个同名的方法,并不是重写 public class DuoTaiDemo02 { public static void main(String[] args) { Fu fu = new Zi(); fu.methed(); //The static method methed() from the type Fu should be accessed in a static way //系统也不建议用对象调用静态方法,应该用类直接调用 } } class Fu { public Fu() {} public static void methed() { System.out.println("Fu staticMethod"); } } class Zi extends Fu { public Zi() {} public static void methed() { System.out.println("Zi staticMethod"); } }
-
构造方法:先执行父类构造方法,加载父类静态成员,在执行子类构造方法
- 可以加载父类的静态成员方法区
- 帮助子类初始化从父类继承下来的成员
注意
私有方法 静态方法 final方法不能被继承,所以不能重写,不能构成多态,所以都是编译时期看左,运行时期看左,只有成员方法运行时期是看右的
3.多态的好处
- 简化代码
- 提高了代码维护性
- 提高了代码的扩展性
4.多态的缺点
多态的缺点:利用多态父类引用无法访问子类所特有的方法
public class DuoTaiDemo04 {
public static void main(String[] args) {
Car c = new Bmw();
c.run();
c.showBrand();
//The method showBrand() is undefined for the type Car
//父类Car没办法识别方法showBrand()
//因为父类没有这方法,遵循 2.访问多态成员的特点
//成员方法:编译时期看左边类型,运行时期看右边类型
//左边在编译时期并没有知道showBrand()方法,所报错
}
}
class Car {
public void run() {
System.out.println("我也不知道怎么跑,想怎么跑就怎么跑!!");
}
}
class Bmw extends Car {
public void run() {
System.out.println("嗖嗖搜地跑");
}
public void showBrand() {
System.out.println("别摸我!");
}
}
解决方法: 向下转型 + i**nstanceof **关键字
4.1向上转型
//格式
[父类类型] 引用变量名 = new [子类类型]( ) ;
4.1.1向上转型的特点
- 子类转化为父类,父类引用指向子类对象,类似于自动进行数据类型转换
- 通过父类引用变量调用的方法是子类覆盖或者继承父类的方法(多态的体现)
- 通过父类引用变量无法调用子类特有的属性和方法(多态的缺点)
4.2向下转型
//格式
[子类类型] 引用变量名 = ( [子类类型] ) 父类引用变量名;
4.2.1向下转型的特点
-
父类转化为子类,父类引用转为子类对象,类似于强制类型转换
-
向下转换的过程中,子类类型与父类创建对象指向的子类类型不同时,会类型转换异常
Car c = new Bmw(); Benz benz = (Benz) c;//java.lang.ClassCastException //原因是向下转型的子类类型并不是创建对象时,父类引用指向的子类对象 //即:c 指的是Bmw,而向下转型的子类类型是Benz
4.3instanceof 关键字
用于解决向下转型发生的类型转换异常
判断左边对象是否属于右边实例
//格式
[对象] instanceof [类];
//返回值类型:boolean
4.4解决方式的缺陷
instanceof 解决类型转异常是有缺陷的
if (c instanceof Bmw) {
Bmw bmw = (Bmw) c;
// 利用向下转型访问子类所特有的方法和属性
bmw.showBrand();
} else if (c instanceof Benz) {
Benz benz = (Benz) c;
benz.showSpeed();
} else if (c instanceof Maslati) {
Maslati maslati = (Maslati) c;
maslati.showMoney();
}
//每当新建一个类,就需要增加一个else if
//问题一:每次修改原码都必须进行测试
//问题而:就算这可修改没什么问题不测试,对于有很多类的情况,就得大量加入else if,这工作量是不合理的
5.多态的表现形式(重载)
//一个方法参数列表不同,在Test类中使用的时候,就可以根据多态调用同一个方法,不同的参数列表
interface IPerson {
void use(Student s);
void use(Student s, Teacher t);
void use(Teacher t, Student s);
void use(Student s, Teacher t, Worker w);
}