“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对象,即它返回受typesClassclazzvariables影响的test.Demo.class

然后,调用clazz.newInstance() 创build由此Class对象表示的类的新实例。 这个类被实例化,就像通过一个带有空参数列表的newexpression式一样。 换句话说,这里实际上相当于一个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注册:

  1. 通过调用Class.forName方法。 这显式加载驱动程序类。 由于它不依赖于任何外部设置,因此使用DriverManager框架推荐使用这种加载驱动程序的方式。 以下代码加载类acme.db.Driver

     Class.forName("acme.db.Driver"); 

    如果已经编写了acme.db.Driver以便加载它会导致一个实例被创build,并且调用DriverManager.registerDriver作为参数 (它应该这样做),那么它就在DriverManager的驱动程序列表中,可用于创build连接。

  2. (……)

在这两种情况下,新加载的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对象。

现在你可以访问你所有的类可见的字段和方法。