[英]Synthetic Class in Java
Java 中的合成類是什么? 為什么要使用它? 我怎樣才能使用它?
Java 具有在運行時創建類的能力。 這些類被稱為合成類或動態代理。
有關詳細信息,請參閱http://java.sun.com/j2se/1.5.0/docs/guide/reflection/proxy.html 。
其他開源庫(例如CGLIB和ASM)也允許您生成合成類,並且比 JRE 提供的庫更強大。
合成類由 AOP(面向方面的編程)庫(例如 Spring AOP 和 AspectJ)以及 ORM 庫(例如 Hibernate)使用。
好吧,我在谷歌上找到了第一個問題的答案:
如果一個類是由編譯器生成的,即它沒有出現在源代碼中,則它可能被標記為合成類。
這只是一個基本定義,但我在論壇帖子中找到了它,沒有任何解釋。 仍在尋找更好的...
合成類/方法/字段:
這些東西對 VM 很重要。 看看下面的代碼片段:
class MyOuter {
private MyInner inner;
void createInner() {
// The Compiler has to create a synthetic method
// to construct a new MyInner because the constructor
// is private.
// --> synthetic "constructor" method
inner = new MyInner();
// The Compiler has to create a synthetic method
// to doSomething on MyInner object because this
// method is private.
// --> synthetic "doSomething" method
inner.doSomething();
}
private class MyInner {
// the inner class holds a syntetic ref_pointer to
// the outer "parent" class
// --> synthetic field
private MyInner() {
}
private void doSomething() {
}
}
}
例如,當您有一個 switch 語句時,java 會創建一個以 $ 開頭的變量。 如果您想看到這樣的示例,請查看其中包含 switch 語句的類的 Java 反射。 當您在類中的任何地方至少有一個 switch 語句時,您就會看到這些變量。
為了回答您的問題,我認為您無法訪問(反射除外)合成類。
如果您正在分析一個您一無所知的類(通過反射)並且需要了解關於該類的非常具體和低級的事情,那么您最終可能會使用與合成類有關的 Java 反射方法。 此處唯一的“用途”是獲取有關該類的更多信息,以便在您的代碼中適當地使用它。
(如果您這樣做,您可能正在構建其他開發人員可以使用的某種框架。)
否則,如果您不使用反射,那么我所知道的合成類就沒有實際用途。
根據這個討論,雖然語言規范描述了類的“isSynthetic”屬性,但實現幾乎忽略了這一點,並且不用於動態代理或匿名類。 合成字段和構造函數用於實現嵌套類(字節碼中沒有嵌套類的概念,只有在源代碼中)。
我認為合成類的概念已經被證明是沒有用的,即沒有人關心一個類是否是合成的。 對於字段和方法,它可能正好用在一個地方:確定在 IDE 類結構視圖中顯示什么 - 您希望在那里顯示普通方法和字段,而不是用於模擬嵌套類的合成方法和字段。 OTOH,您確實希望匿名類出現在那里。
它們是由 JVM 在運行時為調試目的調用內部類的私有成員時創建的
JVM 在運行時為其執行目的創建的方法、字段、類稱為 Synthetic
http://www.javaworld.com/article/2073578/java-s-synthetic-methods.html
http://javapapers.com/core-java/java-synthetic-class-method-field/
Java 中的合成類是什么?
synthetic
類是由Java Compiler生成的.class
文件,它不存在於源代碼中。
synthetic
類的使用示例:匿名內部類
synthetic
類,它是java.text.DigitList內部的匿名內部類DigitList$1.java
這樣的源代碼文件,但它是DigitList.java
一個內部文件為什么要使用它?
它是 Java 編譯器邏輯內部的一種機制,用於生成.class
文件
我怎樣才能使用它?
不,開發人員不直接使用它。
Java 編譯器使用synthetic
生成.class
文件,然后 JVM 讀取.class
文件來執行程序邏輯。
EasyMock 還使用合成類或動態代理在運行時創建接口或抽象類的實現。
當 Java 編譯器編譯某些構造(例如內部類)時,它會創建合成構造; 這些是在源代碼中沒有相應構造的類、方法、字段和其他構造。
用途:合成構造使 Java 編譯器能夠在不更改 JVM 的情況下實現新的 Java 語言功能。 但是,不同的 Java 編譯器實現之間的合成構造可能會有所不同,這意味着 .class 文件也可能因不同的實現而有所不同。
參考: docs.oracle.com
正如各種答案已經指出的那樣,編譯器可以生成不直接對應於源代碼中的某些內容的各種構造(包括類)。 這些必須標記為合成:
類或接口的二進制表示還必須包含以下所有內容:
[...]
11. 如果 Java 編譯器發出的構造與源代碼中顯式或隱式聲明的構造不對應,則必須將其標記為合成的,除非發出的構造是類初始化方法(JVMS §2.9)。
[...]
正如@Holger在對另一個問題的評論中指出的那樣,此類構造的相關示例是表示方法引用和 lambda 的 Class 對象:
System.out.println(((Runnable) System.out::println).getClass().isSynthetic());
System.out.println(((Runnable) () -> {}).getClass().isSynthetic());
輸出:
true
true
雖然沒有明確提到這一點,但它來自15.27.4。 Lambda 表達式的運行時評估:
lambda 表達式的值是對具有以下屬性的類實例的引用:[...]
以及方法引用的幾乎相同的措辭( 15.13.3.方法引用的運行時評估)。
由於在源代碼的任何地方都沒有明確提到這個類,它必須是合成的。
合成類不會出現在您的代碼中:它是由編譯器組成的。 例如,在java 中由編譯器組成的橋接方法通常是合成的。
public class Pair<T> {
private T first;
private T second;
public void setSecond(T newValue) {
second = newValue;
}
}
public class DateInterval extends Pair<String> {
public void setSecond(String second) {
System.out.println("OK sub");
}
public static void main(String[] args) throws NoSuchFieldException, SecurityException {
DateInterval interval = new DateInterval();
Pair pair = interval;
pair.setSecond("string1");
}
}
使用命令javap -verbose DateInterval
,可以看到橋接方法:
public void setSecond(java.lang.Object);
flags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
這是由編譯器組成的; 它不會出現在您的代碼中。
如果我猜對了,合成類是動態生成的,而不必給它一個明確的名稱。 例如:
//...
Thread myThread = new Thread() {
public void run() {
// do something ...
}
};
myThread.start();
//...
這將創建 Thread 的合成子類並覆蓋其 run() 方法,然后實例化它並啟動它。
合成構造是在源代碼中沒有相應構造的類、方法、字段等。 合成構造使 Java 編譯器能夠在不更改 JVM 的情況下實現新的 Java 語言功能。 但是,不同的 Java 編譯器實現之間的合成構造可能會有所不同,這意味着 .class 文件也可能因不同的實現而有所不同。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.