MethodHandles.Lookup.defineClass
在运行时从字节数组生成一个新类.
在什么情况下返回的类可以被垃圾收集?是否在与Lookup对象关联的类加载器的生命周期内保留,或者如果不再引用Class对象,它是否可以进行垃圾回收?
解决方法
通过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.
在像HotSpot这样的JVM上,符号引用“Lazy”被懒散地解析,即在尝试调用Lazy.foo()时,这将最终在动态定义的类中.对于急切解析符号引用的JVM,当调用MethodHandles.Lookup.defineClass时,Lazy类已经存在,因此,将抛出带有“尝试重复定义Lazy”之类的消息的LinkageError.
换句话说,这些动态生成的类与静态编译的类共享相同的名称空间(类加载上下文).像普通类一样在类加载器中注册,只有在定义类加载器变得无法访问时(包括所有定义的类),它们才能获得垃圾收集,就像普通类一样.