Class.forName()与ClassLoader.loadClass() – 哪个用于dynamic加载?
dynamic加载类时,何时适合使用
Class.forName("SomeClass");
何时使用
ClassLoader.getSystemClassLoader().loadClass("SomeClass");
或者,他们是做同样的事情的两种方式吗?
他们是完全不同的!
如Class.forName(String)
的文档中所述,
返回与具有给定string名称的类或接口关联的Class对象。 调用此方法相当于:
Class.forName(className, true, currentLoader)
(这里的true
指你想要初始化这个类吗? )
另一方面, ClassLoader.loadClass(String)
:
调用这个方法相当于调用
loadClass(name, false)
。
(在这里,布尔与初始化无关;但如果检查loadClass(String,boolean)文档,您将看到它所做的只是加载类,而不是初始化它)。
第一个( Class.forName("SomeClass");
)将:
- 使用加载调用此代码的类的类加载器
- 初始化类(即所有的静态初始化器将被运行)
另一个( ClassLoader.getSystemClassLoader().loadClass("SomeClass");
)会:
- 使用“系统”类加载器( 可覆盖 )
- 不是初始化这个类(比如,如果你使用它来加载一个JDBC驱动,它将不会被注册,而且你将不能使用JDBC!)
假设您正在编写将在诸如Tomcat之类的容器上执行的Web应用程序。 Tomcat所做的是为每个Web应用程序创build一个类加载器(以便稍后可以卸载该Web应用程序并释放内存 – 您需要一个专用的类加载器才能工作!)。 在这种情况下,你可以看到这两个调用将产生完全不同的结果!
有关类加载和初始化的更详细的(和权威的)信息,请查看Java语言规范最新(第三版)的12.2和12.4节。
Class.forName()
使用调用者的类加载器并初始化类(运行静态初始化器等)
loadClass
是一个ClassLoader
方法,所以它使用一个明确提供的加载器,并在第一次使用时懒惰地初始化类。
请注意,还有一个Class.forName()也需要ClassLoader
。
他们基本上是做同样的事情。 虽然使用的ClassLoader可能会有所不同。 Class.forName使用您从this.getClass()。getClassLoader()获得的类加载器,而您的其他代码指定使用系统类加载器。
在大多数应用程序中,这将是相同的类加载器,但在更复杂的环境中,例如J2EE应用程序或小应用程序,情况可能并非如此。
ClassLoader是一个抽象类,但是你的应用程序总是被一个类加载器加载,可能会有自定义的类加载器,比如networking类加载器或者任何其他的源代码。
另一方面,Class本身表示类和接口,而Class类有一个forName函数,它使用当前类加载器,默认情况下应用程序正在运行该类加载器以加载类。
这里是Class.forName的源代码,然后调用调用类加载器。
public static Class<?> forName(String className) throws ClassNotFoundException { return forName0(className, true, ClassLoader.getCallerClassLoader()); }
http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/ClassLoader.html
http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Class.html#forName(java.lang.String )
提示:Primordial类加载器http://docs.oracle.com/javase/1.4.2/docs/guide/security/spec/security-spec.doc5.html
-
Class.forName()
加载并初始化类。 在类加载器子系统中,它执行所有三个阶段,即加载,链接和初始化阶段。 -
ClassLoader.loadClass()
行为,这会延迟初始化,直到第一次使用类。 在类加载器子系统中,它只执行两个阶段,即加载和链接阶段。
例如:
class MyClass { static { System.out.println("static block in MyClass"); } } public class TestCase1 { public static void main(String... args) throws Throwable { Class.forName("A"); } } //The above TestCase1 produce output: static block in MyClass public class TestCase2 { public static void main(String... args) throws Throwable { ClassLoader.getSystemClassLoader().loadClass("MyClass"); } } //The above TestCase2 not produce any output
我喜欢在Java加载类…
这实际上取决于运行应用程序的上下文。如果从Web上下文使用它,而不是只使用命令行程序,则会得到不同的结果。
我也遇到了问题,取决于你的ClassPath看起来像什么,我期待发生。
这篇 JavaWorld文章解释了很多。