学习关于多态方法方法动态绑定,有一点让我疑惑。《java核心技术卷一》和廖雪峰的官方java教程都给出了非常权威的讲解,但仍让我产生一些疑问,这里是我的一点思考。
这里我仍采用廖雪峰老师的示例:
class Person{
public void run(){
System.out.println("Person.run");
}
}
class Student extends Person{
@override
public void run(){
System.out.println("Student.run");
}
}
Person p = new Student();
廖老师堆以上示例说:那么,一个实际类型为Student,引用类型为Person的变量,调用其run()方法,调用的是Person还是Student的run()方法?
可见p的实际类型为Student,引用类型为Person。
根据《java核心技术卷一》第164页第四点:程序运行并且采用动态绑定调用方法时,虚拟机必须调用与x所引用对象的实际类型对应的那个方法。假设x的实际类型是D,它是C的子类。如果D类定义了方法f(String),就会调用这个方法;否则,将在D类的超类中寻找f(String),以此类推。
和廖雪峰的java教程面向对象基础中的多态一节:Java的实例方法调用是基于运行时的实际类型的动态调用,而非变量的声明类型。
按照《java核心技术》和廖老师的讲解,p调用的run方法是Student类的方法,即结果为"Student.run"。
p.run();
// "student.run"
事实也的确如此,没毛病。但来看另一种情况:
class Student extends Person{
@override
public void run(){
System.out.println("Student.run");
}
// 在子类中定义自身特有的方法 public void show(){
System.out.println("my own method");
}
}
Person p = new Student();
按照《java核心技术》和廖老师的讲解,p的实际类型为Student,那么就应该能调用自己的show方法。可实际上并不能。
p.show() // 会报错
这里百思也得不到他的姐姐了,问题出在哪呢?
p的实际类型不是Student嘛,为什么调用不了show方法呢?这说不通。
因此,我猜测,p的实际类型并不是Student,而是Person!
那这么说来《java核心技术》和廖老师还能错了?我认为《核心技术》书和廖老师并没有错,而是容易让初学者理解错。
问题出在哪?我猜测是如廖老师的讲解,run方法调用时p的实际类型的确是Student。p的实际类型可以为Student,但是需要一个条件。这个条件就是run方法的调用,也就是存在子类重写父类方法的情况。
只有存在子类重写父类方法且调用此重写方法时,p的实际类型暂时可以看成是子类Student。但是除此之外,p的类型始终为Person。这样貌似就说的通了。
// 第一种Person p1 = new Studnet();
// 第二种Student s = new Student();
Person p2 = (Person) s;
我认为以上两种写法是等价的,既然第二种写法p2的类型为Person,那么第一种也应该是Person。这是以上我大胆猜测的简单证明。
注:以上纯粹属于个人观点,如有不妥之处,望指正
本文有引用《java核心技术卷一》一书和廖雪峰的官方网站java教程的部分内容
若未获得本人同意,请勿转载本文