我一直在学习,因为我参加了考试,而且我对大多数Java没有太多问题,但我偶然发现了一个我无法解释的规则。这是一段代码片段:
public class A {
public int method(Object o) {
return 1;
}
public int method(A a) {
return 2;
}
}
public class AX extends A {
public int method(A a) {
return 3;
}
public int method(AX ax) {
return 4;
}
}
public static void main(String[] args) {
Object o = new A();
A a1 = new A();
A a2 = new AX();
AX ax = new AX();
System.out.println(a1.method(o));
System.out.println(a2.method(a1));
System.out.println(a2.method(o));
System.out.println(a2.method(ax));
}
返回:
1 3 1 3
虽然我希望它能回归:
1 3 1 4
为什么a2的类型决定了在AX中调用哪个方法?
我一直在阅读重载规则和继承,但这似乎模糊不清,以至于我无法找到确切的规则。任何帮助将不胜感激。
这些方法调用的行为由Java Language Specification(参考部分8.4.9)规定和描述。
调用方法时(第15.12节),在编译时使用实际参数的数量(以及任何显式类型参数)和参数的编译时类型来确定将被调用的方法的签名( §15.12.2)。如果要调用的方法是实例方法,则将在运行时使用动态方法查找(第15.12.4节)确定要调用的实际方法。
在您的示例中,Java编译器确定您正在调用方法的实例的编译类型上最接近的匹配项。在这种情况下:
A.method(AX)
最接近的方法来自类型A,签名为A.method(A)
。在运行时,动态分派是在A的实际类型(它是AX的一个实例)上执行的,因此这是实际调用的方法:
AX.method(A)
我会以更简单的方式澄清它。看你何时用超类引用创建子类对象,就像你在这里一样。
总有一件事情在你的脑海中留意,当你用超类引用调用时,没有问题对象属于子类,它将进入超类,使用此名称检查方法以及是否存在适当的签名。
现在如果它会找到它,那么它会检查它是否被覆盖?如果是,它将转到像这里的子类方法它去了。另一个明智的是它将执行相同的超类方法。
我可以举出它的例子...只是隐藏
public int method(A a) {
return 3;
}
方法和检查你的答案你会得到1 2 1 2,为什么因为它优先参考。因为你覆盖它而不是调用它,所以它给它3 .. !!希望它大而易懂。快乐学习
a2引用为A和JVM首先使用引用(不是您期望的实际对象)。