最近我偶然发现了Java测试并发现了一种奇怪的行为。
class MainOne {
private int i = 5;
public MainOne() {
System.out.println("MainOne says that I is " + getI());
}
public int getI() {
System.out.println("MainOne getI was used");
return i;
}
}
public class TheTest extends MainOne {
private static int i = 10;
public TheTest() {
System.out.println("TheTest says that I is " + super.getI());
}
public int getI() {
System.out.println("TheTest getI was used");
return i;
}
public static void main(String[] args) {
TheTest test = new TheTest();
}
}
结果是:
使用了测试getI
MainOne说我才10岁。
使用MainOne getI
TheTest说我是5岁
问题是,发生了什么?为什么Base类使用它后代的方法?
答案 0 :(得分:5)
这完全是关于执行顺序和构造函数继承。 TheTest
构造函数隐式调用super
MainOne
构造函数。
所以
public TheTest() {
System.out.println("TheTest says that I is " + super.getI());
}
来电
public MainOne() {
System.out.println("MainOne says that I is " + getI());
}
由于多态性而调用覆盖getI()
。
public int getI() {
System.out.println("TheTest getI was used");
return i;
}
此处的i
是static i
中声明的TheTest
。最后
super.getI());
被调用,使用MainOne
的{{1}}。
你得到
i
请注意,多态不适用于字段,并且该字段(无论TheTest getI was used
MainOne says that I is 10.
MainOne getI was used
TheTest says that I is 5
还是实例)可能会隐藏父类中相同名称的字段。
答案 1 :(得分:0)
这个问题有两点需要注意。
MainOne
public TheTest() {
System.out.println("TheTest says that I is " + super.getI());
}
强行将此调用转到超类,即使该方法被覆盖。
子类中的字段i
被定义为static
字段
根据该字段是否为静态,结果存在差异。当从getI()
构造函数调用重写的TheTest
时,调用将转到MainOne
类方法。但是,当发生此调用时,TheTest
类的实例字段尚未初始化为指定的值(但仅为默认值)。
如果i
中的字段TheTest
是实例字段,则getI()
将打印0而不是10。
这里很难说明调用顺序的细节。但是,如果您想了解更多详细信息,请参阅以下内容。
new TheTest()
-> super() - implicitly invoke default constructor
-> inside MainOne() constructor
-> System.out.println("MainOne says that I is " + getI());
-> this results in a getI() invocation
-> since getI() is overridden by subclass
-> invoke on TheTest instance, not MainOne class.
-> TheTest's instance fields not given the assigned values
-> TheTest's static fields have got the assigned values
<- string concatenation completes for System.out.println()
<- MainOne constructor (or the super) is completed
<- super() completes
-> System.out.println("TheTest says that I is " + super.getI());
-> this results in a getI() invocation
-> however explicit super.getI() forcefully goes to super class
-> invoke on MainOne (super) instance, not TheTest class.
<- string concatenation completes for System.out.println()
<- new TheTest() constructor completes
希望这有助于您进一步了解细节。