Java中为何私有方法按引用类型调用、公有方法按对象类型调用?
Java私有方法调用解析的疑问解答
先看你的代码和实际输出:
代码
class Main { public static void main(String[] args) { Main m = new Sub(); m.sing(); System.out.println(m.foo()+""); } public void sing(){ System.out.println("hohoho"); } private boolean foo(){ return false; } } class Sub extends Main{ public boolean foo(){ return true; } public void sing(){ System.out.println("lalala"); } }
实际输出
lalala false
核心解释
你的“对象类型决定方法调用”的假设只适用于可重写的实例方法,并非所有方法都遵循这个规则,这是你困惑的根源。
1. 为什么foo()调用了Main类的实现?
- Main类中的
foo()是私有方法,私有方法在Java中是静态绑定的:编译器在编译阶段就会根据变量的引用类型(这里是Main)确定要调用的方法,完全不会考虑运行时的实际对象类型(Sub)。 - Sub类中的
foo()并不是重写Main的foo(),而是一个全新的独立方法——因为私有方法无法被子类继承,Sub根本看不到Main的foo(),所以它的foo()是自己定义的、和Main的foo()毫无关联的方法。 - 当你用
Main类型的引用m调用foo()时,编译期就已经锁定了Main类的私有foo(),运行时不会做动态查找,自然不会执行Sub的foo()。
2. 关于“对象类型决定方法调用”的适用范围
这个规则仅针对可重写的实例方法,需要满足三个条件:
- 非
private - 非
static - 非
final
这类方法才会在运行时根据对象的实际类型进行动态绑定,也就是你理解的“对象类型决定调用哪个实现”。而私有方法、静态方法、final方法都是静态绑定,编译期就确定了方法版本。
3. 为什么sing()调用了Sub类的实现?
sing()是public的实例方法,属于可重写的范围,所以运行时会根据实际对象类型Sub,调用Sub中重写后的sing()方法,输出lalala。
内容的提问来源于stack exchange,提问作者DrinkandDerive
相关产品推荐
相关产品推荐

