4

最近我偶然发现了 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();
    }
    
}

结果是:

使用了Test getI

MainOne 说我是 10 岁。

MainOne getI 被使用

TheTest 说我是 5

问题是,发生了什么?基类如何使用它的后代方法?

4

2 回答 2

6

这都是关于执行顺序和构造函数继承的。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's i

你因此得到

TheTest getI was used

MainOne says that I is 10.

MainOne getI was used

TheTest says that I is 5

请注意,多态性不适用于字段,并且字段(无论是static实例还是实例)可能会隐藏父类中的同名字段。

于 2013-11-02T20:36:35.847 回答
0

这个问题有两点需要注意。

  1. super.getI() 内部调用MainOne

    public TheTest() {
        System.out.println("TheTest says that I is " + super.getI());
    }
    

    即使该方法被覆盖,此调用也会强制转到超类。

  2. 子类中的字段i定义为static字段

    根据该字段是否为静态,结果会有所不同。当getI()TheTest构造函数调用重写时,调用转到MainOne类方法。但是,当此调用发生时,类的实例字段TheTest尚未初始化为分配的值(但只有默认值)。

    如果中的字段iTheTest实例字段,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
    

希望这有助于您进一步了解细节。

于 2013-11-03T06:31:31.170 回答