Java 教程

Java 控制語句

面向物件程式設計

Java 內建類

Java 檔案處理

Java 錯誤和異常

Java 多執行緒

Java 同步

Java 網路

Java 集合

Java 介面

Java 資料結構

Java 集合演算法

高階 Java

Java 雜項

Java API 和框架

Java 類引用

Java 有用資源

Java - 隱藏類



Java 15 引入了**隱藏類**,其他類的位元組碼無法直接使用這些類。這些**隱藏類**旨在供在執行時生成類的框架使用,並使用反射來使用它們。

**隱藏類**定義為基於訪問控制上下文的成員,並且可以獨立於其他類解除安裝。

此提案 (JEP 371) 旨在透過提供一個標準 API 來定義不可發現且生命週期有限的**隱藏類**,從而改進 JVM 上的所有語言。JDK 框架或外部框架可以動態生成類,這些類可以生成隱藏類。

JVM 語言嚴重依賴於動態類生成以實現靈活性和效率。

目標

以下是此增強功能的目標列表

  • 框架應該能夠將類定義為框架的不可發現的實現細節,這些類既不能連結到其他類,也不能使用反射發現。
  • 使用不可發現的類擴充套件訪問控制巢狀。
  • 積極解除安裝隱藏類將幫助框架根據需要定義儘可能多的隱藏類,而不會降低效能。
  • 棄用非標準 API,misc.Unsafe::defineAnonymousClass,以便在將來的版本中刪除。

建立隱藏類

為了建立隱藏類,我們必須建立一個 Lookup 例項,如下所示

MethodHandles.Lookup lookup = MethodHandles.lookup();

一旦 Lookup 例項可用,我們就可以使用 defineHiddenClass() 方法使用隱藏類的位元組陣列來建立隱藏類。

 Class<?> hiddenClass = lookup.defineHiddenClass(getByteArray(), true, ClassOption.NESTMATE).lookupClass();

隱藏類的位元組陣列可以使用隱藏類的類路徑檢索。

public static byte[] getByteArray() throws IOException {
   InputStream stream = Util.class.getClassLoader().getResourceAsStream("com/tutorialspoint/Util.class");
   byte[] bytes = stream.readAllBytes();
   return bytes;
}

一旦載入了 hiddenClass 類,我們就可以使用 getConstructor() 方法建立其例項。

 Object hiddenClassObj = hiddenClass.getConstructor().newInstance();

使用隱藏類例項,我們可以獲取方法,然後像下面這樣執行它

Method method = hiddenClassObj.getClass().getDeclaredMethod("square", Integer.class);
// call the method and get result
Object result = method.invoke(hiddenClassObj, 3);

由於隱藏類是隱藏的,並且不能使用反射例項化,因此其隱藏屬性為 true,規範名稱為 null。

建立和使用隱藏類的示例

以下示例顯示了隱藏類的建立和使用。首先,我們建立了一個公共類 Util,如下所示

package com.tutorialspoint;

public class Util {
   public Integer square(Integer n) {
      return n * n;
   }
}

現在,我們已將此類建立為隱藏類,並訪問其方法以獲取數字的平方。

package com.tutorialspoint;

import java.io.IOException;
import java.io.InputStream;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup.ClassOption;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Tester {
   public static void main(String args[]) throws IllegalAccessException, IOException, InstantiationException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
      // create the lookup object	   
      MethodHandles.Lookup lookup = MethodHandles.lookup();
      // define the hidden class using the byte array of Util class
      // Using NESTMATE option so that hidden class has access to 
      // private members of classes in same nest
      Class<?> hiddenClass = lookup.defineHiddenClass(getByteArray(),
         true, ClassOption.NESTMATE).lookupClass();

      // get the hidden class object
      Object hiddenClassObj = hiddenClass.getConstructor().newInstance();

      // get the hidden class method
      Method method = hiddenClassObj.getClass().getDeclaredMethod("square", Integer.class);

      // call the method and get result
      Object result = method.invoke(hiddenClassObj, 3);

      // print the result
      System.out.println(result);

      // as hidden class is not visible to jvm, it will print hidden
      System.out.println(hiddenClass.isHidden());

      // canonical name is null thus this class cannot be instantiated using reflection 
      System.out.println(hiddenClass.getCanonicalName());

   }
   public static byte[] getByteArray() throws IOException {
      InputStream stream = Util.class.getClassLoader().getResourceAsStream("com/tutorialspoint/Util.class");
      byte[] bytes = stream.readAllBytes();
      return bytes;
   }
}

讓我們編譯並執行以上程式,這將產生以下結果 -

9
true
null
廣告