MethodHandles.lookup()。defineClass保留

时间:2018-10-08 22:37:25

标签: java java-9

MethodHandles.Lookup.defineClass在运行时从字节数组生成新类。

在什么情况下可以对返回的类进行垃圾回收?它是否保留在与Lookup对象关联的类加载器的生命周期中,或者如果不再引用Class对象,是否可以对其进行垃圾回收?

1 个答案:

答案 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() {
    }
}

Try it online

此示例动态定义一个Lazy类,该类的foo()方法在被调用时将打印hello from dynamic class

在像HotSpot这样的JVM上,符号引用“ Lazy”被延迟解析,即,当尝试调用Lazy.foo()时,它将最终在动态定义的类中结束。对于急切解决符号引用的JVM,在调用LazyMethodHandles.Lookup.defineClass类将已经存在,因此,将抛出一条带有诸如“试图为Lazy尝试重复定义”的消息的LinkageError。 / p>

换句话说,这些动态生成的类与静态编译的类共享相同的名称空间(类加载上下文)。像普通类一样在类加载器中注册,它们只能在定义类加载器(包括其所有已定义的类)变得不可访问时(如普通类一样)获取垃圾。