JEP 371- 隱藏類 介紹

簡介

本文介紹最新的JEP 371提案: 隱藏類,目前該提案正在徵求社區意見建議


創建者: Mandy Chung

類型:特性

作用於:SE

狀態:提議中

目標版本:15

組件:core-libs / java.lang.invoke

討論:valhalla dash dev at openjdk dot java dot net

預審:by Alex Buckley, David Holmes, John Rose, Maurizio Cimadamore, Paul Sandoz

認可: by John Rose

創建: 2019/03/13 17:37

更新:2020/04/01 23:24

問題跟蹤: 8220607


JEP 371- 隱藏類 介紹

摘要

介紹隱藏的類,這些類是其他類的字節碼不能直接使用的類。 隱藏類適用於在運行時生成類並通過反射間接使用它們的框架。 隱藏類可以定義為訪問控制嵌套的成員,並且可以獨立於其他類進行卸載。


目標

允許框架將類定義為框架的不可發現的實現細節,以便它們不能被其他類鏈接,也不能通過反射來發現。

支持使用不可發現的類擴展訪問控制嵌套。

支持主動卸載不可發現的類,因此框架可以靈活地定義所需數量。

棄用非標準API sun.misc.Unsafe :: defineAnonymousClass,以棄用該API以在將來的發行版中將其刪除。

請勿以任何方式更改Java編程語言。


非目標

支持sun.misc.Unsafe :: defineAnonymousClass的所有功能(例如恆定池補丁程序)不是目標。


提案背景原因

基於JVM構建的許多語言實現都依賴於動態類生成,以提高靈活性和效率。 例如,對於Java語言,javac不會在編譯時將lambda表達式轉換為專用的類文件,而是發出字節碼,該字節碼可動態生成並實例化一個類以在需要時產生與lambda表達式相對應的對象。 同樣,非Java語言的運行時通常使用動態代理來實現那些語言的高級功能,這些代理也可以動態生成類。

語言實現者通常希望動態生成的類在邏輯上成為靜態生成的類的實現的一部分。 此意圖建議了動態生成的類所需的各種屬性:

  • 不可發現性。 通過名字獨立地被發現不僅是不必要的,而且是有害的。 它破壞了動態生成的類僅是靜態生成的類的實現細節的目標。
  • 訪問控制。 可能希望將靜態生成的類的訪問控制上下文擴展為包括動態生成的類。
  • 生命週期。 動態生成的類可能只需要有限的時間,因此在靜態生成的類的生命週期內保留它們可能會不必要地增加內存佔用。 針對這種情況的現有解決方法(例如,按類裝載器)既麻煩又效率低下。

不幸的是,定義類的標準API(ClassLoader :: defineClass和Lookup :: defineClass)對於該類的字節碼是動態生成(在運行時)還是靜態生成(在編譯時)並不重要。 這些API始終定義一個可見的類,該類將在每次在同一加載器層次結構中的另一個類嘗試鏈接該名稱的類時使用。 因此,該類可能比所需的類更容易發現或具有更長的生命週期。 此外,如果嵌套的宿主類事先知道成員類的名稱,則API只能定義一個將充當嵌套成員的類。 實際上,這可以防止動態生成的類成為嵌套成員。

如果標準API可以定義無法發現的且具有有限生命週期的隱藏類,則動態生成類的JDK內部和外部框架都可以定義隱藏類。 這將提高所有基於JVM的語言實現的效率。 例如:

  • java.lang.reflect.Proxy 可以定義隱藏類以充當實現代理接口的代理類;
  • java.lang.invoke.StringConcatFactory 可以生成隱藏類來保存常量連接方法;
  • java.lang.invoke.LambdaMetaFactory可以生成隱藏的nestmate類,以保存訪問封閉變量的lambda主體;
  • JavaScript引擎可以為從JavaScript程序轉換的字節碼生成隱藏的類,因為當引擎不再使用它們時,這些類將被卸載。

描述

Java 7中引入的Lookup API允許類獲取提供對類,方法和字段的反射訪問的查找對象。 至關重要的是,無論最終使用查找對象的代碼是什麼,反射訪問總是在最初獲得查找對象的類(查找類)的上下文中發生。 實際上,查找對象將查找類的訪問權限傳輸給接收該對象的任何代碼。

Java 9通過引入方法Lookup :: defineClass(byte [])增強了查找對象的傳輸功能。 根據提供的字節,此方法在與最初獲得查找對象的類相同的上下文中定義一個新類。 也就是說,新定義的類與查找類具有相同的定義類加載器,運行時程序包和保護域。

該JEP建議擴展Lookup API以支持定義只能通過反射訪問的隱藏類。 JVM在字節碼鏈接期間無法發現隱藏的類,也不能通過顯式使用類加載器的程序(例如,通過Class :: forName和ClassLoader :: loadClass)發現隱藏的類。 當隱藏的類不再可訪問時,可以將其卸載,也可以共享一個類加載器的生存期,以便僅在對類加載器進行垃圾回收時才將其卸載。 (可選)可以將隱藏類創建為訪問控制嵌套的成員。

為簡便起見,此JEP稱“隱藏類”,但應理解為表示隱藏類或接口。 同樣,“普通類”表示普通類或接口,即ClassLoader :: defineClass的結果。


更多詳細,請參考原始文章,後面太長了,就是描述他們準備怎麼實現


分享到:


相關文章: