为什么在构造函数调用之前初始化实例变量?

时间:2013-09-16 14:08:58

标签: java constructor

我有以下这段代码:

public abstract class UCMService{
    private String service;     

    protected DataMap dataMap = new DataMap(); 

    protected class DataMap extends HashMap<String,String> {

        private static final long serialVersionUID = 4014308857539190977L;

        public DataMap(){
            System.out.println("11111");
            put("IdcService",service);
        }
    }

    public UCMService(String service){
        System.out.println("2222");
        this.service = service;
    }
}

现在在控制台中,System.out.println构造函数的DataMap正在UCMService的构造函数之前执行。

我想知道为什么会这样。

2 个答案:

答案 0 :(得分:34)

这是因为在编译时,编译器会将您在声明位置完成的每个初始化移动到类的每个构造函数。因此UCMService类的构造函数被有效地编译为:

public UCMService(String service){
    super();  // First compiler adds a super() to chain to super class constructor
    dataMap = new DataMap();   // Compiler moves the initialization here (right after `super()`)
    System.out.println("2222");
    this.service = service;
}

因此,显然DataMap()构造函数在print类的UCMService语句之前执行。同样,如果你的UCMService类中有更多的构造函数,初始化将被移动到所有构造函数。


让我们看一个简单类的字节代码:

class Demo {
    private String str = "rohit";

    Demo() {
        System.out.println("Hello");
    }
}

编译此类,并执行命令 - javap -c Demo。您将看到构造函数的以下字节代码:

Demo();
    Code:
       0: aload_0
       1: invokespecial #1   // Method java/lang/Object."<init>":()V
       4: aload_0
       5: ldc           #2   // String rohit
       7: putfield      #3   // Field str:Ljava/lang/String;
      10: getstatic     #4   // Field java/lang/System.out:Ljava/io/PrintStream;
      13: ldc           #5   // String Hello
      15: invokevirtual #6   // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      18: return

您可以在第7行看到putfield指令,将字段str初始化为"rohit",这位于print语句之前(第15行的说明)

答案 1 :(得分:13)

简短回答
因为规范是这样说的。

答案很长
构造函数无法使用内联初始化字段会很奇怪。

您希望能够写

SomeService myService = new SomeService();
public MyConstructor() {
    someService.doSomething();
}