一、多态的概念
父类引用指向子类对象(内存堆区的地址)
二、多态的实现的必要条件
1 存在继承关系
2 存在方法重写
3 父类引用指向子类对象
三、多态访问成员
1 访问成员变量
编译时期看左边的类型,如果左边类型中没有该变量则编译报错
程序运行时期看左边类型,左边类型的变量的值就是运行的结果
2 访问成员方法
编译时期看左边的类型,如果左边类型中没有该方法则编译报错
程序运行时期看右边类型,即程序会执行右边类型的方法
3 访问构造方法
多态访问子类构造方法时会先访问父类构造方法
我们可以利用这一特性来帮助子类初始化父类继承过来的成员
4 访问静态方法
编译时期看左边的类型,如果左边类型中没有该方法则编译报错
程序运行时期看右边类型,即程序会执行右边类型的方法
四、多态的优点
1 简化代码
2 提高程序的扩展性和可维护性
五、多态的缺点
使用父类引用无法直接访问子类所特有的成员,需要向下转型,即父类引用转为子类对象(强制转换),且向下转型的过程中如果没有转换为真实子类类型,会出现类型转换异常(ClassCastException),故每次在向下转型之前需要做一个类型判断
六、代码演示
public class DuoTaiDemo {
public static void main(String[] args) {
// Car c = new BMW(); //父类引用指向子类对象new BMW(),形成多态结构
c.run(); //此时访问的是宝马重写父类的方法,而宝马自己特有的方法却无法通过c.bmwRun()直接访问了
BMW bmw = (BMW) c; // 利用向下转型
bmw.bmwRun(); //此时即可访问宝马特有的bmwRun()方法了
c = new Benz(); //父类引用指向子类对象newBenz(),形成多态结构
c.run(); //此时访问的是奔驰重写父类的方法,而奔驰自己特有的方法却无法通过c.benzRun()直接访问了
Benz benz = (Benz) c;
benz.benzRun();
BMW bmw2 = (BMW) c;
bmw2.fillOil();
System.out.println(c instanceof BMW); //c instanceof BMW:判断c是否是BMW类的一个实例,返回值为布尔类型
System.out.println(c instanceof Benz); //c instanceof Benz:判断c是否是Benz类的一个实例,返回值为布尔类型
Car c = new Benz();
c.run();
if (c instanceof Benz) { //做类型转换判断:如果对象c是奔驰的一个实例
Benz benz = (Benz) c; //则执行向下转型
benz.benzRun(); //然后执行奔驰特有的benzRun()方法
} else if (c instanceof BMW) { //如果对象是宝马的一个实例
BMW b = (BMW) c; //则执行向下转型
b.BMWRun(); //然后执行宝马特有的BMWRun()方法
}
}
}
class Car {
public void run() {
System.out.println("父类Car的方法run()");
}
}
class BMW extends Car {
@Override
public void run() {
System.out.println("宝马重写了父类的方法run()");
}
public void bmwRun() {
System.out.println("宝马自己特有的方法bmwRun()");
}
}
class Benz extends Car {
@Override
public void run() {
System.out.println("奔驰重写了父类的方法run( )");
}
public void benzRun() {
System.out.println("奔驰自己特有的方法benzRun() ");
}
}
class BYD extends Car {
@Override
public void run() {
System.out.println("比亚迪重写了父类的方法run( )");
}
public void bydRun() {
System.out.println("比亚迪自己特有的方法bydRun()");
}
}