我有以下这段代码:
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
的构造函数之前执行。
我想知道为什么会这样。
答案 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();
}