Java合成建構式 sysnthetic constructor簡介。
Synthetic constructor是指原本不存在於原始碼的建構式,而是在編譯時由complier生成的。
參考java.lang.Constroctor
的isSynthetic()
說明,可找到此方法定義在介面java.lang.Member
的isSynthetic()
:如果成員是透過complier引入返回true,反之返回false。
Returns true if this member was introduced by the compiler; returns false otherwise.
再參考Java 8的程式語言規格書(Java Language Specification)的13.1 The Form of a Binary的第11項說明:由Java編譯器生成的建構式若不存在於原始碼,不論顯性或隱性,則必須標註為synthetic,除非生成的建構式為類別初始方法(e.g. <init>
)。
A construct emitted by a Java compiler must be marked as synthetic if it does not correspond to a construct declared explicitly or implicitly in source code, unless the emitted construct is a class initialization method (JVMS §2.9)..
那什麼情況下complier會生成這些原本不在原始碼中的建構式呢?一個典型例子為取得私有的靜態巢狀類別(private static nested class)實例。
例如下面的SyntheticConstructorDemo
中有個私有的靜態巢狀類別PrivateNestedClass
。
私有的巢狀類別如沒有顯性地寫出建構式,則預設的隱性建構式為私有的(private),不過 Java語言允許外部類別(outer class)可直接建構私有的巢狀類別,然而私有的巢狀類別建構式是私有的,所以實際是透過complier生成的synthetic constructor來建構實例。
SyntheticConstructorDemo.java
ackage com.abc.demo;
import java.lang.reflect.Constructor;
public class SyntheticConstructorDemo {
public static void main(String[] args) {
PrivateNestedClass privateNestedClass = new PrivateNestedClass(); // 建構私有的巢狀類別
Constructor<?>[] constructors = PrivateNestedClass.class.getDeclaredConstructors();
System.out.println(constructors.length); // 2
Constructor<?> constructor1 = constructors[0];
System.out.println(constructor1.getName() + ".isSynthetic()=" + constructor1.isSynthetic()); // com.abc.demo.SyntheticConstructorDemo$PrivateNestedClass isSynthetic()=false
Constructor<?> constructor2 = constructors[1];
System.out.println(constructor2.getName() + ".isSynthetic()=" + constructor2.isSynthetic()); // com.abc.demo.SyntheticConstructorDemo$PrivateNestedClass isSynthetic()=true
}
/** 私有的靜態巢狀類別 */
private static class PrivateNestedClass {
}
}
在SyntheticConstructorDemo
的main()
中建構PrivateNestedClass
的實例,並透過反射取得PrivateNestedClass
的建構式,可看出除了預設的私有隱性建構式外,還有另一個complier生成的建構式,其isSynthetic()
結果為true。執行結果如下。
2
com.abc.demo.SyntheticConstructorDemo$PrivateNestedClass.isSynthetic()=false
com.abc.demo.SyntheticConstructorDemo$PrivateNestedClass.isSynthetic()=true
如果以Java 1.6的javac
去編譯SyntheticConstructorDemo.java
會編譯出三個class檔為:
SyntheticConstructorDemo.class
SyntheticConstructorDemo$PrivateNestedClass.class
SyntheticConstructorDemo$1.class
再以javap
反組譯SyntheticConstructorDemo$PrivateNestedClass.class
會印出以下JVM指令集可看到兩個建構式,第二個非私有的com.abc.demo.SyntheticConstructorDemo$PrivateNestedClass(com.abc.demo.SyntheticConstructorDemo$1)
即為complier額外生成的synthetic constructor,接受的參數為編譯時另外產生的SyntheticConstructorDemo$1.class
。外部類別透過此synthetic constructor來建構PrivateNestedClass
。
$ javap -c -p -l SyntheticConstructorDemo.PrivateNestedClass
Warning: File ./SyntheticConstructorDemo$PrivateNestedClass.class does not contain class SyntheticConstructorDemo.PrivateNestedClass
Compiled from "SyntheticConstructorDemo.java"
class com.abc.demo.SyntheticConstructorDemo$PrivateNestedClass {
private com.abc.demo.SyntheticConstructorDemo$PrivateNestedClass();
Code:
0: aload_0
1: invokespecial #2 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 21: 0
com.abc.demo.SyntheticConstructorDemo$PrivateNestedClass(com.abc.demo.SyntheticConstructorDemo$1);
Code:
0: aload_0
1: invokespecial #1 // Method "<init>":()V
4: return
LineNumberTable:
line 21: 0
}
以javap
反組譯SyntheticConstructorDemo
印出以下,可看到main()
方法中的Code 5: invokespecial
調用了synthetic constructor com.abc.demo.SyntheticConstructorDemo$PrivateNestedClass(com.abc.demo.SyntheticConstructorDemo$1)
。
$ javap -c -p -l SyntheticConstructorDemo
Warning: File ./SyntheticConstructorDemo.class does not contain class SyntheticConstructorDemo
Compiled from "SyntheticConstructorDemo.java"
public class com.abc.demo.SyntheticConstructorDemo {
public com.abc.demo.SyntheticConstructorDemo();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 5: 0
public static void main(java.lang.String[]);
Code:
0: new #2 // class com/abc/demo/SyntheticConstructorDemo$PrivateNestedClass
3: dup
4: aconst_null
5: invokespecial #3 // Method com/abc/demo/SyntheticConstructorDemo$PrivateNestedClass."<init>":(Lcom/abc/demo/SyntheticConstructorDemo$1;)V
8: astore_1
9: ldc #2 // class com/abc/demo/SyntheticConstructorDemo$PrivateNestedClass
...
LineNumberTable:
line 8: 0
line 10: 9
...
}
沒有留言:
張貼留言