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.classSyntheticConstructorDemo$PrivateNestedClass.classSyntheticConstructorDemo$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
...
}
沒有留言:
張貼留言