Skip to content

标题: ClassLoader.loadClass()与Class.forName()的区别

创建: 2020-08-06 11:31 更新: 2020-08-06 16:37 链接: https://scz.617.cn/web/202008061131.txt

参看:

What's the difference between ClassLoader.load(name) and Class.forName(name) - irreputable [2011-07-10] https://stackoverflow.com/questions/6638959/whats-the-difference-between-classloader-loadname-and-class-fornamename

stackoverflow上另有一篇高赞回答同类问题,那篇根本就没说到点上,不看也罢。

多数时候用这两个API:


/ * java.lang.ClassLoader.loadClass(String) : Class / public Class<?> loadClass(String name)


/ * java.lang.Class.forName(String) : Class / public static Class<?> forName(String className)


它们各有一个功能更强大的重载版本:


/ * java.lang.ClassLoader.loadClass(String, boolean) : Class / protected Class<?> loadClass(String name, boolean resolve)


/ * java.lang.Class.forName(String, boolean, ClassLoader) : Class / public static Class<?> forName(String name, boolean initialize, ClassLoader loader)


考虑如下代码:


class X { static { System.out.println( "Init Class X" ); }

int foo ()
{
    return 1;
}

Y bar ()
{
    return new Y();
}

}

ClassLoader.loadClass( "X", resolve )

若resolve为true,上述代码加载目标类时尝试加载目标类所引用的其他类,就本例 而言,尝试加载Y。若resolve为false,上述代码只会加载X,不会加载Y。直到有人 调用X.bar(),Y才会被加载。

若resolve为true,同时加载Y失败,则加载X亦失败。若resolve为false,即使Y不存 在,仍可加载X。

ClassLoader.loadClass( "X" )

这个public版本内部resolve为false,正合吾意。

ClassLoader.loadClass()仅加载目标类,不对之初始化,不触发。可以对 被加载后的目标类进行反射操作,遍历构造函数、方法、成员等等。

Class.forName( "X", initialize, loader )

若initialize为true,加载目标类后会对之初始化,触发,静态代码块被执 行,就本例而言,会输出"Init Class X"。若initialize为false,加载目标类后不 对之初始化,不触发

Class.forName( "X" )

这个版本相当于:

Class.forName ( "X", true, ClassLoader.getClassLoader ( Reflection.getCallerClass() ) )

注意,是相当于,实际调的是native版本Class.forName0()。Class.forName0()内部 会调用ClassLoader.loadClass(),后者更底层。

Class.forName Class.forName0 ClassLoader.loadClass


2020-08-06 15:25 涂改

试了一下关于resolve为true时的情况,发现加载X的时候,并没有去加载Y。验证方 式是采用反射调用loadClass(),把参数resolve设为true,然后在JVM参数中加上 "-verbose:class"打印被加载的类,结果发现只有X被加载的记录。看了一下 resolveClass0()在hotspot中的实现(jvm.cpp的JVM_ResolveClass),发现是个空方 法。是不是我的验证方式有问题啊?

我是在JDK 1.8上测试的,所看hotspot源码也是1.8的,只是小版本有点差别。

2020-08-06 16:43 scz

这是个好问题。前文是irreputable在2011年所写,我并未验证resolve这一部分,仅 仅是翻译了一下。不排除Java版本变化的可能,但我亦未就此查看2011年的JVM实现。 你的实验应该没有问题,稳妥起见,在此附上你的实验记录,以免他人踩坑。