簡體   English   中英

Java 記錄反思與綜合方法

[英]Java Records Reflection and Synthetic Methods

基於較舊的Java (7) 語言規范 (13.1.7)

Java 編譯器引入的任何在源代碼中沒有相應構造的構造必須標記為合成的,但默認構造函數、class 初始化方法以及枚舉 class 的值和 valueOf 方法除外。

在較新的 ( Java (17) Language Specifications (13.1.7) : ) 上,措辭更改為:

如果 Java 編譯器發出的構造不對應於源代碼中顯式或隱式聲明的構造,則必須將其標記為合成構造,除非發出的構造是 class 初始化方法(JVMS §2.9)。

我想知道這將如何應用於為 java記錄 (JEP 395)的組件創建的訪問器方法

例如

record ARecord(int a){}

會有一個方法int a()但沒有代碼表示這種方法,根據舊 JLS 的措辭,這種方法是由編譯器添加的,所以我希望它是合成的,但它不是,因為它可以被證實在JShell上運行以下兩行

jshell
|  Welcome to JShell -- Version 17.0.1
|  For an introduction type: /help intro

jshell> record ARecord(int a){}
|  created record ARecord

jshell> ARecord.class.getDeclaredMethod("a").isSynthetic();
$2 ==> false

jshell>

我問的原因是因為我想在運行時使用反射(或任何其他編程方式)來確定 class 上的哪些元素具有匹配的代碼結構,基本上那些具有代表它們的代碼,意思是:

對於以下代碼

record ARecord(int a){

  pubic void someMethod() {}

}

實體將有 2 種方法( asomeMethod ), a沒有代表它的代碼而someMethod有,我需要一種方法來根據該標准區分那些方法

我想知道這是否是因為它被視為隱式聲明是其代碼隱式定義為組件的一部分

就是這樣。 請注意舊規范如何只說“合成”應該標記在構造上

源代碼中沒有相應的構造

隱式聲明的Enum.valuesEnum.valueOf 那時候,顯然只有這兩個是隱式聲明的(在新規范使用該短語的意義上)。 :D

另一方面,新規范說

不對應於源代碼中顯式或隱式聲明的構造

請注意,此措辭會自動處理Enum異常,但也會處理此后添加的大量隱式聲明的內容。 這包括記錄組件。

來自Java 17 規范 §8.10.3。 記錄成員

此外,對於每個記錄組件,記錄 class 具有與記錄組件同名的方法和一個空的形式參數列表。 這種顯式或隱式聲明的方法稱為訪問器方法。

...

如果記錄 class 的記錄組件未顯式聲明訪問器方法,則該記錄組件的訪問器方法隱式聲明 [...]

方法a在您的組件中隱式聲明,因此它不是合成的。

一般來說(可能有我不知道的例外情況),合成結構是語言規范未指定的結構,但編譯器的特定實現需要它才能工作。 規范基本上是說此類結構必須在二進制文件中標記為“合成的”。 在此處查看一些示例。

javac會完全忽略具有synthetic標志的類型的任何成員。 Javac 的行為就像這些東西根本不存在一樣。

因此,很明顯,您為記錄獲得的“吸氣劑”不是合成的。 如果是的話,就不可能從.java代碼中調用它們——調用它們的唯一方法是編寫一個 hacky javac克隆編譯對合成的訪問,或者使用字節碼操作來刪除合成標志,或者發出直接字節碼,或者使用反射。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM