作者:我心飞翔 | 来源:互联网 | 2022-12-02 18:17
MethodHandles.Lookup.defineClass
在运行时从字节数组生成一个新类.
在什么情况下返回的类可以被垃圾收集?是否在与Lookup
对象关联的类加载器的生命周期内保留,或者如果Class
不再引用该对象,是否可以对其进行垃圾回收?
1> Holger..:
创建的类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
调用时已经存在,因此,LinkageError
将抛出带有"尝试重复定义Lazy"的消息.
换句话说,这些动态生成的类与静态编译的类共享相同的名称空间(类加载上下文).像普通类一样在类加载器中注册,只有在定义类加载器变得无法访问时(包括所有定义的类),它们才能获得垃圾收集,就像普通类一样.
@Eugene我们不是在谈论重写访问控制,而是关于该方法创建的类的匿名性质.官方API可以检查访问权限,就像`MethodHandles.Lookup.defineClass`一样.