为什么 Class.forName 出现在这个 class 的字节码中?
Why does Class.forName appear in the bytecode for this class?
我一直在对 Java 字节码进行一些个人研究,我遇到了一些奇怪的事情。如果我反编译 this class,我会在常量池中找到对 Class.forName()
的引用。但是,源代码中没有引用此方法。
我假设这段代码的某些内容导致 javac 发出一些动态加载 class 的代码,但我不确定为什么会发生这种情况。这让我觉得效率低下,但主要是我只是好奇为什么会这样。
用javap
反汇编代码后,发现源码中有一个方法是不存在的:
static java.lang.Class class$(java.lang.String);
Code:
0: aload_0
1: invokestatic #1 // Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class;
4: areturn
5: astore_1
6: new #3 // class java/lang/NoClassDefFoundError
9: dup
10: invokespecial #4 // Method java/lang/NoClassDefFoundError."<init>":()V
13: aload_1
14: invokevirtual #5 // Method java/lang/NoClassDefFoundError.initCause:(Ljava/lang/Throwable;)Ljava/lang/Throwable;
17: athrow
Exception table:
from to target type
0 4 5 Class java/lang/ClassNotFoundException
看起来这是在为 < JDK1.5 版本编译的字节码中生成的,只要在代码 [1] 中引用了 class 文字。基本上,这个:
if (getClass() == Level.class) {}
变成这样:
if (getClass() == class$("org.apache.log4j.Level")) {}
和 class$()
看起来像这样:
static Class class$(java.lang.String className) {
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
throw new NoClassDefFoundError();
}
}
显然在 JDK1.5 中,ldc_w
指令被赋予了加载 class 常量的能力,并且不再需要 class$()
方法。
我一直在对 Java 字节码进行一些个人研究,我遇到了一些奇怪的事情。如果我反编译 this class,我会在常量池中找到对 Class.forName()
的引用。但是,源代码中没有引用此方法。
我假设这段代码的某些内容导致 javac 发出一些动态加载 class 的代码,但我不确定为什么会发生这种情况。这让我觉得效率低下,但主要是我只是好奇为什么会这样。
用javap
反汇编代码后,发现源码中有一个方法是不存在的:
static java.lang.Class class$(java.lang.String);
Code:
0: aload_0
1: invokestatic #1 // Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class;
4: areturn
5: astore_1
6: new #3 // class java/lang/NoClassDefFoundError
9: dup
10: invokespecial #4 // Method java/lang/NoClassDefFoundError."<init>":()V
13: aload_1
14: invokevirtual #5 // Method java/lang/NoClassDefFoundError.initCause:(Ljava/lang/Throwable;)Ljava/lang/Throwable;
17: athrow
Exception table:
from to target type
0 4 5 Class java/lang/ClassNotFoundException
看起来这是在为 < JDK1.5 版本编译的字节码中生成的,只要在代码 [1] 中引用了 class 文字。基本上,这个:
if (getClass() == Level.class) {}
变成这样:
if (getClass() == class$("org.apache.log4j.Level")) {}
和 class$()
看起来像这样:
static Class class$(java.lang.String className) {
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
throw new NoClassDefFoundError();
}
}
显然在 JDK1.5 中,ldc_w
指令被赋予了加载 class 常量的能力,并且不再需要 class$()
方法。