我正在研究简单的重载覆盖规则,发现了一些有趣的东西。这是我的代码。
package com.demo;
public class Animal {
private void eat() {
System.out.println("animal eating");
}
public static void main(String args[]) {
Animal a = new Horse();
a.eat();
}
}
class Horse extends Animal {
public void eat() {
System.out.println("Horse eating");
}
}
该程序输出以下内容。
动物吃
这是我所知道的:
private void eat()
方法一样,它不一定要在子类中进行访问,因此,由于JLS对其进行了明确定义,因此在这里不会出现方法覆盖的问题。public void eat()
从Horse类中调用方法Animal a = new Horse();
由于多态性,我们的声明是有效的。为什么a.eat()
要从Animal
类中调用方法?我们正在创建一个Horse
对象,为什么为什么要调用Animal类的方法?
我不确定我是否理解您的困惑。根据您所知道的:
您是对的,Horse.eat()
没有被压倒Animal.eat()
(因为它是私有的)。换句话说,当您调用时anAnimal.eat()
,不会发生后期绑定,因此,您只是在调用Animal.eat()
,这就是您所看到的。
从您的其他评论看来,您的困惑似乎是编译器如何决定调用什么。这是一个非常高级的解释:
当编译器看到时Animal a =...; a.eat();
,它将尝试解析要调用的内容。
例如,如果看到的eat()
是一个静态方法,给出a
了Animal
对它的引用,则编译器会将其转换为call Animal.eat()
。
如果它是一个实例方法,并且遇到一个可能被子类覆盖的方法,则编译器将执行的操作是,它不会生成调用特定方法的指令。相反,它将生成指令以从vtable中进行某种查找。从概念上讲,每个对象都有一张小表,键是方法签名,值是对要调用的实际方法的引用。例如,如果在您的情况下Animal.eat()
不是私有的,则Horse的vtable将包含类似的内容["eat()" -> "Horse.eat()"]
。因此,在运行时,给定一个Animal
引用并被eat()
调用,实际上发生的是:使用,从所引用对象的vtable中进行查找eat()
,然后调用关联的方法。(如果裁判指向Horse
,相关的方法将是Horse.eat()
)。在大多数情况下,这就是完成后期绑定魔术的方法。
使用不可能被覆盖的实例方法,编译器会执行与静态方法相似的操作,并生成直接调用该方法的指令。
(以上内容在技术上并不准确,只是一个概念性的插图,供您了解发生的情况)
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句