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
广告