标题: 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实现。 你的实验应该没有问题,稳妥起见,在此附上你的实验记录,以免他人踩坑。