“Class.forName()”和“Class.forName().newInstance()”有什么区别?
和 有什么区别?Class.forName()
Class.forName().newInstance()
我不明白显着的差异(我已经读过一些关于它们的东西!你能帮帮我吗?
和 有什么区别?Class.forName()
Class.forName().newInstance()
我不明白显着的差异(我已经读过一些关于它们的东西!你能帮帮我吗?
也许一个展示如何使用这两种方法的例子将帮助您更好地理解事物。因此,请考虑以下类:
package test;
public class Demo {
public Demo() {
System.out.println("Hi!");
}
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("test.Demo");
Demo demo = (Demo) clazz.newInstance();
}
}
如其javadoc中所述,调用Class.forName(String)
返回与具有给定字符串名称的类或接口关联的Class
对象,即它返回受影响的类型变量。test.Demo.class
clazz
Class
然后,调用 clazz.newInstance()
将创建由此 Class
对象表示的类的新实例。该类被实例化,就好像由具有空参数列表的新
表达式实例化一样。换句话说,这里实际上等效于 a 并返回 一个新的实例。new Demo()
Demo
因此,运行此类将打印以下输出:Demo
Hi!
与传统类的最大区别在于,它允许实例化您在运行时之前不知道的类,从而使您的代码更具动态性。new
newInstance
一个典型的例子是JDBC API,它在运行时加载执行工作所需的确切驱动程序。EJBs 容器、Servlet 容器是其他很好的例子:它们使用动态运行时加载来加载和创建它们在运行时之前什么都不知道的组件。
实际上,如果你想更进一步,看看Ted Neward的论文Depresing Class.forName(),我在上面的段落中转述了它。
编辑(回答OP中作为评论发布的问题):JDBC驱动程序的情况有点特别。如 JDBC API 入门的驱动程序管理器一章中所述:
(...)加载类,并因此通过以下两种方式之一自动注册到 :
Driver
DriverManager
通过调用方法 。这将显式加载驱动程序类。由于它不依赖于任何外部设置,因此这种加载驱动程序的方式是使用框架的推荐方法。以下代码加载该类:
Class.forName
DriverManager
acme.db.Driver
Class.forName("acme.db.Driver");
如果已经编写了
acme.db.Driver
,以便加载它会导致创建一个实例,并且还调用DriverManager.registerDriver
并将该实例作为参数(应该这样做),那么它位于 驱动程序列表中,可用于创建连接。DriverManager
- (...)
在这两种情况下,新加载的类都有责任通过调用 来注册自身。如前所述,这应该在装入类时自动完成。
Driver
DriverManager.registerDriver
要在初始化期间注册自身,JDBC 驱动程序通常使用静态初始化块,如下所示:
package acme.db;
public class Driver {
static {
java.sql.DriverManager.registerDriver(new Driver());
}
...
}
调用会导致类的初始化,从而导致静态初始化块的执行。并且确实会“创建”一个实例,但这只是如何实现(好的)JDBC驱动程序的结果。Class.forName("acme.db.Driver")
acme.db.Driver
Class.forName("acme.db.Driver")
作为旁注,我想提一下,JDBC 4.0(自Java 7以来作为默认包添加)和JDBC 4.0驱动程序的新自动加载功能不再需要所有这些。请参阅 Java SE 6 中的 JDBC 4.0 增强功能。
Class.forName() 为您提供了类对象,这对于反射很有用。此对象具有的方法由 Java 定义,而不是由编写类的程序员定义。它们对于每个班级都是一样的。在它上调用newInstance()会给你一个该类的实例(即调用它相当于调用),你可以在上面调用该类定义的方法,访问可见字段等。Class.forName("ExampleClass").newInstance()
new ExampleClass()