什么是Java中的对象字段初始化和构造函数顺序

时间:2013-12-13 22:57:49

标签: java

我今天早些时候在代码中结束了以下场景(我承认有点奇怪,我已经重构了)。当我运行单元测试时,我发现在超类构造函数运行的时候没有设置字段初始化。我意识到我并不完全理解构造函数/字段初始化的顺序,所以我希望有人向我解释这些发生的顺序。

class Foo extends FooBase {
    String foo = "foobar";

    @Override
    public void setup() {
        if (foo == null) {
            throw new RuntimeException("foo is null");
        }
        super.setup();
    }
}

class FooBase {
    public FooBase() {
        setup();
    }

    public void setup() {

    }
}

@Test
public void testFoo() {
    new Foo();
}

来自JUnit的缩写回溯如下,我想我期望$ Foo。< init>设置foo。

$Foo.setup
$FooBase.<init>
$Foo.<init>
.testFoo

3 个答案:

答案 0 :(得分:7)

是的,在Java中(例如,与C#不同)字段初始值设定项在超类构造函数之后被称为。这意味着在执行字段初始值设定项之前,来自构造函数的任何重写方法调用都将被称为

排序是:

  • 初始化超类(递归调用这些步骤)
  • 执行字段初始值设定项
  • 执行构造函数体(在任何构造函数链接之后,已在步骤1中发生)

基本上,在构造函数中调用非final方法是个坏主意。如果您打算这样做,请清楚地记录 very ,以便任何覆盖该方法的人都知道在执行字段初始值设定项(或构造函数体)之前将调用该方法。

有关详细信息,请参阅JLS section 12.5

答案 1 :(得分:3)

构造函数的第一个操作始终是超类构造函数的调用。没有在类中明确定义的构造函数等同于

public Foo() {
    super();
}

因此,在初始化子类的任何字段之前调用基类的构造函数。你的基类做了一些应该避免的事情:调用一个可覆盖的方法。

由于在子类中重写了此方法,因此它在尚未完全构造的对象上调用,因此将子类字段视为null。

答案 2 :(得分:0)

以下是伪C#/ Java中的多态性示例:

for (int i=0; i< hash[key].size(); i++) {
  auto value = hash[key][i];
  if (value.first == count) {
    value.second.push_back(s);
    inHash = true;
    break;
  }
}

Main函数不知道动物的类型,并且取决于MakeNoise()方法的特定实现的行为。

class Animal
{
   abstract string MakeNoise ();
}

class Cat : Animal {
    string MakeNoise () {
    return "Meow";
    } 
}

class Dog : Animal {
    string MakeNoise () {
    return "Bark";
    }
}

Main () {
    Animal animal = Zoo.GetAnimal ();
    Console.WriteLine (animal.MakeNoise ());
}

出: A是1 A是2 B's 5

我的规则: 1.不要使用声明中的默认值进行初始化(null,false,0,0.0 ...)。 2.如果没有更改字段值的构造函数参数,则首选声明中的初始化。 3.如果由于构造函数参数而改变字段的值,则将初始化放在构造函数中。 4.在练习中保持一致。 (最重要的规则)

class A
{
A(int number)
   {
    System.out.println("A's" + " "+ number);
   }
}

class B
{
A aObject = new A(1);
B(int number)
    {
    System.out.println("B's" + " "+ number);        
    }
A aObject2 = new A(2);
}

public class myFirstProject {   
public static void main(String[] args) {
    B bObj = new B(5);
   }
}

public class Dice
{
private int topFace = 1;
private Random myRand = new Random();

public void Roll()
   {
   // ......
   }
}