Ebb*_*ham 23 java reflection classloader
以下是2个代码段
第一个使用ClassLoader类来加载指定的类
ClassLoader cls = ClassLoader.getSystemClassLoader();
Class someClass = cls.loadClass("TargetClass");
第二个使用Class.forName()来加载指定的类
Class cls = Class.forName("TargetClass");
上述方法之间有什么区别.哪一个用于哪个目的?
Bru*_*eis 48
其他答案非常完整,因为他们探索了其他重载Class.forName(...),并讨论了使用不同ClassLoader的可能性.
然而,他们没有回答你的直接问题:"上述方法之间有什么区别?",它涉及一个特定的超载Class.forName(...).他们错过了一个非常重要的区别.类初始化.
考虑以下课程:
public class A {
static { System.out.println("time = " + System.currentTimeMillis()); }
}
Run Code Online (Sandbox Code Playgroud)
现在考虑以下两种方法:
public class Main1 {
public static void main(String... args) throws Throwable {
final Class<?> c = Class.forName("A");
}
}
public class Main2 {
public static void main(String... args) throws Throwable {
ClassLoader.getSystemClassLoader().loadClass("A");
}
}
Run Code Online (Sandbox Code Playgroud)
第一个类,Main1当运行时,将产生一个输出,如
time = 1313614183558
Run Code Online (Sandbox Code Playgroud)
然而,另一个根本不会产生任何输出.这意味着该类A虽然已加载,但尚未初始化(即,它<clinit>尚未被调用).实际上,您甚至可以在初始化之前通过反射查询类的成员!
你为什么要关心?
有些类在初始化时执行某种重要的初始化或注册.
例如,JDBC指定由不同提供程序实现的接口.要使用MySQL,通常会这样做Class.forName("com.mysql.jdbc.Driver");.也就是说,您加载并初始化类.我从来没有见过那些代码,但显然该类的静态构造函数必须使用JDBC在某处注册类(或其他东西).
如果你这样做了ClassLoader.getSystemClassLoader().loadClass("com.mysql.jdbc.Driver");,你将无法使用JDBC,因为尚未初始化已加载的类(然后JDBC不知道要使用哪个实现,就像你没有加载类一样).
所以,这就是你问的两种方法之间的区别.
Mar*_*urg 14
快速回答(无代码示例)
使用显式ClassLoader cls = <a ClassLoader>;方法,您可以灵活地从不是默认ClassLoader的ClassLoader加载类.在你的情况下,你使用的是默认系统类加载器,所以它提供了类似的总体结果(与最终目标的差异的实例化)作为Class.forName(String name)呼叫,但你可以参考另一个类加载器来代替.
也就是说,Class.forName(String name, boolean initialize, ClassLoader loader)只要您知道ClassLoader是什么,您也可以使用它.
例如,您的基于EAR的应用程序有自己的ClassLoader,其中包含一个XML Parsing库的版本.您的代码通常使用这些类,但在一个实例中,您需要从库的早期版本中获取反序列化类(Application Server恰好在其整个ClassLoader中保存).因此,您可以引用该Application Server ClassLoader.
不幸的是,直到我们得到项目Jigsaw(JDK 8),这比我们想要的更常用:-)
Nee*_*aks 12
在你的具体案例中:
ClassLoader cls = ClassLoader.getSystemClassLoader();
Class someClass = cls.loadClass("TargetClass");
Run Code Online (Sandbox Code Playgroud)
上面的代码将使用系统类加载器加载TargetClass ALWAYS.
Class cls = Class.forName("TargetClass");
Run Code Online (Sandbox Code Playgroud)
第二代码段将加载(并初始化)TargetClass用的是使用加载正在执行该代码行该类的类加载器.如果该类加载了系统类加载器,则这两种方法是相同的(除了类初始化,如Bruno的优秀答案中所述).
哪一个使用?对于使用反射加载和检查类,我建议使用特定的类加载器(ClassLoader.loadClass()) - 它使您可以控制并有助于避免不同环境之间可能存在的模糊问题.
如果您需要加载AND初始化,请使用Class.forName(String, true, ClassLoader).
如何找到合适的类加载器?这取决于您的环境:
Class.getClassLoader()).一般来说,最简单和经过测试的将是使用ClassUtils.forName()Spring(参见JavaDoc).
更深入的解释:
最常见的形式
Class.forName(),即采用单个String参数的形式,总是使用调用者的类加载器.这是加载执行该forName()方法的代码的类加载器.相比之下,ClassLoader.loadClass()是一个实例方法,需要您选择一个特定的类加载器,它可能是也可能不是加载该调用代码的加载器.如果选择一个特定的加载器来加载类对您的设计很重要,那么您应该使用Java 2 Platform,Standard Edition(J2SE)ClassLoader.loadClass()中forName()添加的三参数版本:.Class.forName(String, boolean, ClassLoader)
来源:和之间有什么区别?Class.forName()ClassLoader.loadClass()
此外,SPR-2611在使用时突出了一个有趣的模糊角落案例Class.forName(String, boolean, ClassLoader).
正如Spring问题所示,使用ClassLoader.loadClass()是推荐的方法(当您需要从特定的类加载器加载类时).
| 归档时间: |
|
| 查看次数: |
27249 次 |
| 最近记录: |