“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)
返回与给定string名称关联的类或接口的Class
对象,即它返回受typesClass
的clazz
variables影响的test.Demo.class
。
然后,调用clazz.newInstance()
创build由此Class
对象表示的类的新实例。 这个类被实例化,就像通过一个带有空参数列表的new
expression式一样。 换句话说,这里实际上相当于一个new Demo()
并返回一个Demo
的新实例。
然后运行这个Demo
类来打印下面的输出:
Hi!
与传统的new
的大不同的是, newInstance
允许实例化一个你不知道的类,直到运行时,使你的代码更加dynamic。
一个典型的例子是JDBC API,它在运行时加载执行工作所需的准确驱动程序。 EJB容器,Servlet容器是其他很好的例子:它们使用dynamic运行时加载在运行时加载和创build他们什么都不知道的组件。
其实,如果你想进一步看看Ted Neward的文章Understanding Class.forName() ,我刚刚在上面的段落中进行了解释。
编辑 (回答一个来自OP的问题张贴为注释):JDBC驱动程序的情况有点特别。 正如在JDBC API入门的DriverManager一章中所解释的那样:
(…)一个
Driver
类被加载,因此通过以下两种方式之一自动向DriverManager
注册:
通过调用
Class.forName
方法。 这显式加载驱动程序类。 由于它不依赖于任何外部设置,因此使用DriverManager
框架推荐使用这种加载驱动程序的方式。 以下代码加载类acme.db.Driver
:Class.forName("acme.db.Driver");
如果已经编写了
acme.db.Driver
以便加载它会导致一个实例被创build,并且调用DriverManager.registerDriver
作为参数 (它应该这样做),那么它就在DriverManager
的驱动程序列表中,可用于创build连接。(……)
在这两种情况下,新加载的
Driver
类都有责任通过调用DriverManager.registerDriver
来注册自己。 如前所述,这应该在类加载时自动完成。
要在初始化过程中注册自己,JDBC驱动程序通常使用如下的静态初始化块:
package acme.db; public class Driver { static { java.sql.DriverManager.registerDriver(new Driver()); } ... }
调用Class.forName("acme.db.Driver")
会导致acme.db.Driver
类的初始化,从而导致静态初始化块的执行。 和Class.forName("acme.db.Driver")
确实会“创build”一个实例,但这只是(好)JDBC驱动程序的实现的结果。
作为一个方面说明,我会提到所有这一切都不再需要JDBC 4.0(自Java 7以来作为默认包添加)以及JDBC 4.0驱动程序的新自动加载function。 请参阅Java SE 6中的JDBC 4.0增强 。
Class.forName()给你的类对象,这是reflection有用。 这个对象拥有的方法是由Java定义的,而不是由编写该类的程序员来定义的。 他们对于每个class级都是一样的。 调用newInstance()就会给你一个这个类的实例(即调用Class.forName("ExampleClass").newInstance()
它相当于调用new ExampleClass()
),你可以在其中调用类定义的方法,访问可见的字段等
在JDBC领域, 正常的实践(根据JDBC API)是使用Class#forName()
来加载JDBC驱动程序。 JDBC驱动程序应该在一个静态块内的DriverManager
注册自己:
package com.dbvendor.jdbc; import java.sql.Driver; import java.sql.DriverManager; public class MyDriver implements Driver { static { DriverManager.registerDriver(new MyDriver()); } public MyDriver() { // } }
调用Class#forName()
将执行所有静态初始值设定项 。 这样, DriverManager
可以在getConnection()
通过连接URL在注册的驱动程序中查找关联的驱动程序,大致如下所示:
public static Connection getConnection(String url) throws SQLException { for (Driver driver : registeredDrivers) { if (driver.acceptsURL(url)) { return driver.connect(url); } } throw new SQLException("No suitable driver"); }
但也有错误的 JDBC驱动程序,从org.gjt.mm.mysql.Driver
开始,这是众所周知的例子,它在构造函数而不是静态块中错误地注册自己:
package com.dbvendor.jdbc; import java.sql.Driver; import java.sql.DriverManager; public class BadDriver implements Driver { public BadDriver() { DriverManager.registerDriver(this); } }
让它dynamic工作的唯一方法是事后调用newInstance()
。 否则,您将面临一见无法解释的“SQLException:没有合适的驱动程序”。 再一次,这是JDBC驱动程序中的一个错误 ,而不是你自己的代码。 现在,没有一个JDBC驱动程序应该包含这个错误。 所以你可以(也应该)离开newInstance()
。
1:如果你只对类的静态块感兴趣,那么只能加载类,然后执行静态块,那么你所需要的就是:
Class.forName("Somthing");
2:如果你有兴趣加载类,执行它的静态块,也想访问它的非静态部分,那么你需要一个实例,然后你需要:
Class.forName("Somthing").newInstance();
Class.forName()得到一个Class,Class.forName()的引用。newInstance()尝试使用Class的no-arg构造函数来返回一个新的实例。
“Class.forName()”返回给定名称的类types。 “newInstance()”确实返回这个类的一个实例。
在types上,你不能直接调用任何实例方法,但只能使用类的reflection。 如果你想使用类的对象,你必须创build它的一个实例(和调用“new MyClass()”一样)。
“Class.forName()”的示例
Class myClass = Class.forName("test.MyClass"); System.out.println("Number of public methods: " + myClass.getMethods().length);
“Class.forName()。newInstance()”的示例
MyClass myClass = (MyClass) Class.forName("test.MyClass").newInstance(); System.out.println("String representation of MyClass instance: " + myClass.toString());
只是增加上面的答案,当我们有一个静态代码(即代码块是独立于实例的),需要在内存中,我们可以返回类,所以我们将使用Class.forname(“someName”)否则,如果我们没有静态代码,我们可以去Class.forname()。newInstance(“someName”),因为它会加载对象级代码块(非静态)到内存
Class.forName() – > forName()是Class类的静态方法,它返回用于reflection的Class类对象,而不是用户类对象,因此您只能调用类方法getMethods(),getConstructors()等
如果你关心只运行你的(运行时给定)类的静态块,并只获得你的类的方法,构造函数,修饰符等信息,你可以使用这个对象,你使用Class.forName()
但是如果你想访问或调用你的类方法(你在运行时给出的类),那么你需要有它的对象,所以Class类的newInstance方法为你做。它创build类的新实例,并返回给你你只需要input到你的class级。
前:假设员工是你的class级
Class a = Class.forName(args [0]);
// args [0] = cmd行参数在运行时给类。
Employee ob1 = a.newInstance();
a.newInstance()类似于使用新的Employee()创build对象。
现在你可以访问你所有的类可见的字段和方法。