子类方法的输出不打印?

时间:2017-08-02 15:57:58

标签: java

当我调用printThread时,为什么要打印0和3?

class Super {

    Super() { 
        three(); 
    }

    void three() { 
        System.out.println("three"); 
    }
}

class Child extends Super {
    int three = (int) Math.PI;  // That is, 3

    void three() { 
        System.out.println(three); 
    }

    public static void main(String[] args) {
        Child t = new Child();
        t.three();
    }
}

输出为0和3 但它应该是3和3

2 个答案:

答案 0 :(得分:1)

当您致电new SomeType(..)时,首先new会创建SomeType的实例,其字段设置为default values (适用于{{ 1}}对于int 0,对象引用boolean)为false

稍后通过 构造函数 代码完成对象的正确初始化。这就是为什么负责初始化字段的代码在每个构造函数的开头移动(在null调用之后,因为子类中的代码通常依赖于超类设置)。所以

super()

编译为

class Child extends Super {
    int three = (int) Math.PI;  // That is, 3

由于在class Child extends Super { int three = 0;//initialization to proper value is moved to constructors // | Child(){ // | super(); // | three = (int) Math.PI; //<--------------------+ } ... } 字段正确初始化之前调用了super(),因此其值仍设置为three

超类的构造函数调用0方法但由于它在Child类中被重写,因为polymorphism,调用了three();的代码。由于该代码的打印值为Child#three,并且尚未进行正确的初始化,因此您首先看到其默认值three(由0运算符设置)。

构造函数完成作业后,您通过new第二次调用three(); 。此时t.three();已正确初始化为three3的结果),因此您看到了(int) Math.PI;

为避免此类问题,请不要在构造函数中使用可在子类中重写的方法。直接使用字段,或使用私有,最终或静态方法。

答案 1 :(得分:0)

如果您单步执行此操作,three()将永远是子类的方法(您永远不会调用Super中的实现)。

此外,three()中对Super()的第一次调用实际上将在Child的其余构造函数之前运行,因此第一次调用为0(子对象不是完全初始化了。)