9

我有这个演示代码:

class Test2 extends Test {
    public int number = 0;

    @Override
    public void set(){
        number = 1;
        info();
    }

    @Override
    public void info(){
        System.out.println(number);
    }
}

public class Test {
    public Test(){
        set();
    }

    public void set(){
    }

    public void info(){
    }

    public static void main(String[] args){
        Test2 object = new Test2();
        object.info();
    }
}

代码给出了这个输出:

1
0

为什么?我期望这个输出:

1
1

在我看来,主函数调用 Test2 类的构造函数来创建对象。构造函数自动调用超类的构造函数。此构造函数调用被覆盖的方法 set()。因此调用了 Test2 类的方法 set()。此方法设置字段并调用写入数字的 info() 方法。然后主函数再次调用创建对象的 info() 方法。

数字字段正确设置为第一行输出为“1”。但是为什么第二行包含 0?似乎根本没有设置该字段。你能解释一下吗?

我应该怎么做才能得到我期望的行为?提前致谢!

4

3 回答 3

18
class Test2 {
    public int number = 0;
}

相当于

class Test2 {
    public int number;

    public Test2() {
        super();
        number = 0;
    }
}

因此,通过调用超级构造函数,该字段number被设置为 1。在从超级构造函数返回后,number执行对 0 的赋值。

只需删除分配,它的行为就会如您所愿。

于 2012-08-23T21:53:10.723 回答
2

如果说 Animal 扩展 Dog 并且你调用 Animal a = new Dog()

然后步骤顺序如下

  1. Animal 的静态字段被初始化

  2. 执行动物的静态块

  3. Dog 的静态字段已初始化<如果 Animal 无论如何更改它们,它们将被重新初始化>

  4. Dog 的静态块被执行

  5. 动物的非静态字段已初始化如果动物无论如何更改它们,它们将被重新初始化>

  6. 动物构造函数被执行

  7. 狗初始化的非静态字段<如果动物改变它们,它们将被重新初始化>

  8. Dog 构造函数被执行

于 2014-05-04T11:22:59.480 回答
1

您的代码违反了 Java 中的一条黄金法则——永远不要在构造函数中调用可以被子类覆盖的方法——即此类方法应该是私有的。

当 Test2 中的默认构造函数完成时,它已经覆盖了通过初始化器分配给它的初始值 1 public int number = 0;

于 2012-08-23T21:59:01.700 回答