“很少有程序员意识到类的构造函数和方法可以在初始化之前运行”

时间:2011-11-17 18:05:44

标签: java initialization

在官方Java指南“Programming with assertions”中说明了这一点 (页面上的最后一段)

  

很少有程序员意识到类的构造函数和方法可以在初始化之前运行。当发生这种情况时,很可能该类的不变量尚未建立,这可能会导致严重和微妙的错误。

这是什么意思?这是什么时候发生的?我在日常使用Java时是否需要关注它?

3 个答案:

答案 0 :(得分:29)

基本上,他们谈论以下情况:

public class Foo {
    public static Foo INSTANCE = new Foo(); // Prints null

    public static String s = "bar";

    public Foo() {
        System.out.println(s);
    }
}

正如您所看到的,在这种情况下,构造函数在静态字段s的初始化程序之前运行,i。即在完全初始化类之前。这只是一个简单的例子,但是当涉及多个类时它会变得更加复杂。

这不是你在日常工作中经常看到的东西,但你需要意识到这种可能性,并在编写代码时避免使用它。

答案 1 :(得分:5)

例如,考虑构造函数中的虚方法调度。

class Foo {
   Foo() {
      int a = bar();        
      b = 7;
   }

   private int b;

   protected int baz() { assert b == 7; return b; } ;

   protected abstract int bar();
}

如果一个子类碰巧在baz的实现中调用了bar,那么他们就会遇到这个断言。该对象尚未完成构造,因此Foo基类处于某种状态。

答案 2 :(得分:0)

我认为它们意味着逻辑初始化。例如,您的类A具有方法init(),必须在使用任何业务方法之前调用它。但是使用这个类的其他程序员还没有阅读手册并写了new A().foo()。在这种情况下,foo()可能无法正常工作。在这种情况下,断言可能是有用的。您可以在开头检查init()未被调用并抛出断言。

构造函数也是如此。当有人扩展你的A类时可能会发生这种情况:

class B extends A {
    B() {
        foo(); // init() must be called before foo!
    }
}