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

我有以下这段代码:

public abstract class UCMService{ private String service; protected DataMap dataMap = new DataMap(); protected class DataMap extends HashMap { 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; } } 

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

我想知道为什么会这样。

这是因为在编译时,编译器会将您在声明位置完成的每个初始化移动到类的每个构造函数。 因此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()构造函数在UCMService类的print语句之前执行。 同样,如果您的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."":()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行的指令)

简短回答
因为规范说的如此。

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

你希望能够写作

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