Java继承基类使用派生类方法

Java继承基类使用派生类方法,java,inheritance,Java,Inheritance,最近我偶然发现了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 ge

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

梅因说我10岁了

使用了MainOne-getI

考试说我5岁


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

这是关于执行顺序和构造函数继承的
test
构造函数隐式调用
super
MainOne
构造函数

所以

召唤

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
这里是
测试中声明的
静态i
。最后

super.getI());
使用
MainOne
i
调用

你因此得到

TheTest getI was used

MainOne says that I is 10.

MainOne getI was used

TheTest says that I is 5

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

在这个问题中有两点需要注意

  • super.getI()在
    MainOne内部调用

    public TheTest() {
        System.out.println("TheTest says that I is " + super.getI());
    }
    
    即使方法被重写,此调用也会强制转到超类

  • 子类中的字段
    i
    定义为
    static
    字段

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

    如果测试中的字段
    i
    是一个实例字段,
    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
    
    newthetest()
    ->super()-隐式调用默认构造函数
    ->在MainOne()构造函数中
    ->println(“MainOne说我是”+getI());
    ->这将导致一个getI()调用
    ->因为getI()被子类重写
    ->在测试实例上调用,而不是在一个类上调用。
    ->测试的实例字段未指定指定值
    ->测试的静态字段具有指定的值
    然而,显式的super.getI()强制转到super类
    ->在MainOne(超级)实例上调用,而不是在Test类上调用。
    
    什么意思?它们在构造函数中被调用。但是多态性是如何开始的呢?基类在调用getI()方法时不应该知道它的派生类。@基类不知道,但JVM知道。这是后期绑定的结果。哦,这是有道理的。非常感谢。不过,这是一个棘手的情况。Rogar考虑阅读多态性以及它是如何实现的。您可以开始了解有关后期绑定的一些详细信息。
    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