多态的含义
- 同一个对象,在不同时刻表现出来的不同形态
多态的前提和体现
- 有继承或实现关系
- 有方法的重写
- 有父类引用指向子类对象, 接口的引用指向是实现类的对象
多态的成员访问特点
- 构造方法
- 和继承一样,每个构造方法默认第一行都会有super()去访问父类的无参构造, 当然这建立在你没有手动添加super()方法
- 成员变量
- 编译看父类,执行看父类
- 成员方法
- 编译看父类,执行看子类(子类的方法包括继承父类的方法)
public class Test02 {
public static void main(String[] args) {
Father f = new Son();
/*对于成员变量而言,无论是编译还是运行,都只看对象初始化时的左边(也就是父类)*/
System.out.println(f.a); // 30 由此可见其访问的是父类的变量
//System.out.println(f.b); 因为父类中没有该变量
/*对于成员方法而言,编译看左边(父类),执行看右边(子类)*/
// f.method(); 报错 因为父类没有这个方法,在编译阶段就报错了
f.show(); // 子类的show()方法 由此可见其执行的是子类的show()方法
}
}
class Father {
int a = 30;
public void show() {
System.out.println("父类的show()方法");
}
}
class Son extends Father {
int a = 10;
int b = 20;
@Override
public void show() {
System.out.println("子类的show()方法");
}
public void method() {
System.out.println("子类的method()方法");
}
}
优缺点
- 多态的优点: 提高代码的扩展性
- 定义方法的时候,使用父类型作为参数,该方法就可以接收这父类的任意子类对象
- 定义方法的时候, 使用父类作为方法的返回值类型 , 该方法可以返回此父类任意子类对象
- 定义变量时 , 用父类类型变量接收子类类型对象
- 多态的缺点: 不能访问子类的特有成员
多态的转型
- 向上转型: 把子类类型的对象赋值给父类类型变量 Father f = new Son();
- 向下转型: 把父类类型的数据赋值给子类类型的变量 Son s = (Son)f;
- 优点: 解决多态中不能调用子类特有成员的弊端
public abstract class Animal {
public abstract void eat();
}
class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗吃肉");
}
public void lookHome() {
System.out.println("狗看家");
}
}
class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
public void catchMouse() {
System.out.println("猫抓老鼠");
}
}
class Pig extends Animal {
@Override
public void eat() {
System.out.println("猪拱白菜");
}
public void sleep() {
System.out.println("猪特别能睡");
}
}
public class Test1 {
public static void main(String[] args) {
Animal animal = new Dog(); // 向上转型
useAnimal(new Dog());
useAnimal(new Cat());
useAnimal(new Pig());
}
public static void useAnimal(Animal animal) {
animal.eat();
if(animal instanceof Dog){
Dog dog = (Dog) animal; // 向下转型
dog.lookHome();
}else if(animal instanceof Cat){
Cat cat = (Cat) animal; // 向下转型
cat.catchMouse();
}else if(animal instanceof Pig){
Pig pig = (Pig) animal; // 向下转型
pig.sleep();
}
}
}
/*
执行结果:
狗吃肉
狗看家
猫吃鱼
猫抓老鼠
猪拱白菜
猪特别能睡
*/
多态转型注意点
- 如果被转的引用类型变量,对应的实际类型和目标类型不是同一种类型,那么在转换的时候就会出现ClassCastException
public class Test3 {
public static void main(String[] args) {
Animal animal = new Dog(); // 向上转型
Dog dog = (Dog) animal; // 向下转型
// 报错: ClassCastException 原因是该animal的本质是狗,
// 你可以说它是动物,但却不能说它是猫
Cat cat = (Cat) animal;
}
}
解决转型安全隐患
- 关键字 : instanceof
- 使用格式:
- 对象名 instanceof 引用数据类型
- 通俗的理解:判断关键字左边的变量,是否是右边的类型,返回boolean类型结果
public class Test3 {
public static void main(String[] args) {
Animal animal = new Dog(); // 向上转型
Dog dog = (Dog) animal; // 向下转型
System.out.println(animal instanceof Animal); // true
System.out.println(animal instanceof Dog); // true
System.out.println(animal instanceof Cat); // false
}
}
- 可以看出由Dog对象向上转型成为Animal对象的animal,本质上属于Dog类和Animal类,并不属于Cat类