为什么Class.forName出现在这个类的字节码中?

时间:2016-12-24 19:55:50

标签: java classloader bytecode

我一直在用Java字节码进行一些个人研究,但我发现有点奇怪。如果我反编译this class,我会在常量池中找到对Class.forName()的引用。但是,源代码中没有引用此方法。

我假设有关此代码的一些事情导致javac发出一些动态加载类的代码,但我不确定为什么会这样。它让我觉得效率低下,但主要是我只是好奇为什么会发生这种情况。

1 个答案:

答案 0 :(得分:2)

在用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

看起来这是在为版本&lt;编译的字节码中生成的。只要代码 [1]中引用了类文字,就会出现JDK1.5。基本上,这个:

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$()方法。