Polymorphism
一个事物的多种形态
对象的多态性:父类的引用指向子类的对象
Person test=new man; //man为people的子类
Java引用变量有两个类型:编译时类型和运行时类型。编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。
- 若编译时类型和运行时类型不一致,就出现了对象的多态性
- 多态情况下,
- 编译时:看的是父类的引用(父类中不具备子类特有的方法)
- 运行时:看的是子类的对象(实际运行的是子类重写父类的方法)
当调用子父类同名同参数的方法时,实际执行时子类重写父类的方法
——虚拟方法调用(Virtual Method Invocation)
有了对象的多态性以后,我们在编译期,只能调用父类中声明的方法,但在运行期,我们实际执行的是子类重写父类的方法。
总结:编译,看左边;执行,看右边
对象能执行哪些方法,主要看对象左边的类型,和右边的关系不大!
父类型,可以指向子类,但是不能调用子类独有的方法
public class AnimalTest{
public static void main (String[] args){
Animal test=new Animal();
test.func(new Dog());//Animal animal=new Dog();
test.func(new Cat());//Animal animal=new Cat();
}
public void func(Animal animal){
animal.eat();
animal.shout();
}
}
class Animal{
public void eat(){
System.out.println("动物:进食");
}
public void shout(){
System.out.println("动物:叫");
}
}
class Dog extends Animal{
public void eat(){
System.out.println("狗吃骨头");
}
public void shout(){
System.out.println("汪!汪!汪!");
}
}
class Cat extends Animal{
public void eat(){
System.out.println("猫吃鱼");
}
public void shout(){
System.out.println("喵!喵!喵!");
}
}
结果为
狗吃骨头 汪!汪!汪! 猫吃鱼 喵!喵!喵!
若无多态性,Java实现以上功能需要
public void func(Dog dog){
dog.eat();
dog.shout();
}
public void func(Cat cat){
cat.eat();
cat.shout();
}
使用前提
- 类的继承
- 方法的重写
对象的多态性,只适用于方法,不适用于属性(编译和运行都看左边)
向下转型:用强制类型转换符号有了对象的多态性以后,内存中实际上是加载了子类特有的属性和方法的,但是由于变量声明为父类类型,导致编译时,只能调用父类中声明的属性和方法。子类特有的属性和方法不能调用
Person p=new Man; Man m=(Man) p;
使用强转时,可能出现ClassCastException的异常
Man m=(Woman) w; //此时就可能出现ClassCastException的异常instanceof关键字
Java 的保留关键字。它的作用是测试它左边的对象是否是它右边的类的实例,返回 boolean 的数据类型
a instanceof A:判断对象a是否是类A的实例。如果是,返回true;如果不是,返回false。
为了避免在向下转型时出现ClassCastException的异常,我们现在向下转型之前,先进行instanceof的判断,一旦返回true,就向下转型。如果返回false,不进行向下转型。
Person p=new Man;
if(p instanceof woman){
woman w=(woman) p;
w.workHard();
System.out.println("Woman")
}//返回false,无事发生
if(p instanceof Man){
Man m=(Man) p;
m.workHard();
System.out.println("Man")
}
//正常执行
当a instanceof A返回true、B为A的父类
则此时a instanceof B也返回true
向下转型的几种问题-
编译时通过,运行时报错
Person p=new Woman(); Man m=(man) p; //运行时出现ClassCastException的异常 Person p2=new Person(); Man m2=(Man) p2; //new的对象中没有Man的某些属性,所以不能强转
-
编译不通过
Man m=new Woman(); //Woman不是Man的子类
-
编译通过,运行也通过
Object o=new Woman(); Person p=(Person) o; //可行,因为Woman继承了父类的所有属性



