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;
}
一旦加载了隐藏类,我们就可以使用 getConstructor()
方法创建其实例。
Object hiddenClassObj = hiddenClass.getConstructor().newInstance();
使用隐藏类实例,我们可以获取方法并执行它,如下所示:
Method method = hiddenClassObj.getClass().getDeclaredMethod("square", Integer.class);
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 {
MethodHandles.Lookup lookup = MethodHandles.lookup();
Class<?> hiddenClass = lookup.defineHiddenClass(getByteArray(), true, ClassOption.NESTMATE).lookupClass();
Object hiddenClassObj = hiddenClass.getConstructor().newInstance();
Method method = hiddenClassObj.getClass().getDeclaredMethod("square", Integer.class);
Object result = method.invoke(hiddenClassObj, 3);
System.out.println(result);
System.out.println(hiddenClass.isHidden());
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