MethodHandles.Lookup.defineClass
在运行时从字节数组生成新类。
在什么情况下可以对返回的类进行垃圾回收?它是否保留在与Lookup
对象关联的类加载器的生命周期中,或者如果不再引用Class
对象,是否可以对其进行垃圾回收?
答案 0 :(得分:6)
通过MethodHandles.Lookup.defineClass
创建的类像其他任何类一样在定义类加载器中注册,并且可以像普通类一样通过名称进行引用。在解析此类之前,它们甚至可以取代静态编译的类,例如以下示例:
import java.lang.invoke.MethodHandles;
import java.nio.charset.StandardCharsets;
public class LookupDynamicClass {
public static void main(String[] args) throws IllegalAccessException {
MethodHandles.Lookup lookup = MethodHandles.lookup();
lookup.defineClass(("Êþº¾\0\0\0005\0\26\11\0\11\0\12\10\0\13\12\0\14\0"
+"\15\7\0\16\7\0\17\1\0\3foo\1\0\3()V\1\0\4Code\7\0\20\14\0\21\0\22\1\0"
+"\30hello from dynamic class\7\0\23\14\0\24\0\25\1\0\4Lazy\1\0\20java/"
+"lang/Object\1\0\20java/lang/System\1\0\3out\1\0\25Ljava/io/PrintStream;"
+"\1\0\23java/io/PrintStream\1\0\7println\1\0\25(Ljava/lang/String;)V\6\0"
+"\0\4\0\5\0\0\0\0\0\1\0\11\0\6\0\7\0\1\0\10\0\0\0\25\0\2\0\0\0\0\0\11²\0"
+ "\1\22\2¶\0\3±\0\0\0\0\0\0").getBytes(StandardCharsets.ISO_8859_1));
Lazy.foo();
}
}
interface Lazy {
static void foo() {
}
}
此示例动态定义一个Lazy
类,该类的foo()
方法在被调用时将打印hello from dynamic class
。
在像HotSpot这样的JVM上,符号引用“ Lazy
”被延迟解析,即,当尝试调用Lazy.foo()
时,它将最终在动态定义的类中结束。对于急切解决符号引用的JVM,在调用Lazy
时MethodHandles.Lookup.defineClass
类将已经存在,因此,将抛出一条带有诸如“试图为Lazy尝试重复定义”的消息的LinkageError
。 / p>
换句话说,这些动态生成的类与静态编译的类共享相同的名称空间(类加载上下文)。像普通类一样在类加载器中注册,它们只能在定义类加载器(包括其所有已定义的类)变得不可访问时(如普通类一样)获取垃圾。