Answers:
也许一个示例演示如何使用两种方法将有助于您更好地理解事物。因此,请考虑以下类:
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中所述,调用将返回与具有给定字符串名称的类或接口关联的对象,即它返回受type变量影响的对象。Class.forName(String)
Class
test.Demo.class
clazz
Class
然后,调用创建此 对象表示的类的新实例。如同通过带有空参数列表的表达式实例化该类。换句话说,这实际上等于a 并返回的新实例。clazz.newInstance()
Class
new
new Demo()
Demo
Demo
因此,运行此类将输出以下输出:
Hi!
与传统new
方法的最大区别在于,它newInstance
可以实例化一个直到运行时才知道的类,从而使代码更具动态性。
一个典型的示例是JDBC API,该API在运行时加载执行工作所需的确切驱动程序。EJB容器,Servlet容器是另一个很好的例子:它们使用动态运行时加载来加载和创建在运行时之前一无所知的组件。
实际上,如果您想走得更远,请看一下Ted Neward的论文《理解Class.forName()》,我在上一段中对此进行了解释。
编辑(从发表为评论的OP中回答问题):JDBC驱动程序的情况有点特殊。如《 JDBC API入门》中DriverManager章节所述:
(...)
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());
}
...
}
调用Class.forName("acme.db.Driver")
导致acme.db.Driver
类的初始化,并因此导致静态初始化块的执行。并且 Class.forName("acme.db.Driver")
确实会“创建”一个实例,但这只是实现(良好)JDBC驱动程序的结果。
附带说明一下,我提到JDBC 4.0(自Java 7开始作为默认包添加)以及JDBC 4.0驱动程序的新自动加载功能不再需要所有这些功能。请参阅Java SE 6中的JDBC 4.0增强功能。
DriverManager.registerDriver
。调用Class.forName
JDBC驱动程序会导致其初始化,进而导致静态块的执行。请查看java2s.com/Open-Source/Java-Document/Database-DBMS/…作为示例。因此,实际上这是驱动程序内部的一个特殊情况。
在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
可以通过连接URL在已注册的驱动程序中找到关联的驱动程序,其过程getConnection()
大致如下:
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
众所周知的示例开始,该驱动程序错误地将自身注册在了Constructor中,而不是在静态块中:
package com.dbvendor.jdbc;
import java.sql.Driver;
import java.sql.DriverManager;
public class BadDriver implements Driver {
public BadDriver() {
DriverManager.registerDriver(this);
}
}
使它动态运行的唯一方法是newInstance()
事后致电!否则,您将面对无法解释的“ SQLException:没有合适的驱动程序”。再一次,这是JDBC驱动程序中的错误,而不是您自己的代码中的错误。如今,没有一个JDBC驱动程序应包含此错误。因此,您可以(并且应该)离开newInstance()
。
1:如果您只对类的静态块感兴趣,则仅加载类会执行静态块,然后您需要做的就是:
Class.forName("Somthing");
2:如果您有兴趣加载类,执行其静态块并且还想访问其非静态部分,则需要一个实例,然后需要:
Class.forName("Somthing").newInstance();
“ Class.forName()”返回给定名称的Class-Type。“ newInstance()”确实返回此类的实例。
在类型上,您不能直接调用任何实例方法,而只能对类使用反射。如果要使用该类的对象,则必须创建该类的实例(与调用“ 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()方法多少次,仅在执行静态块后就不会多次:
包forNameMethodDemo;
公共类MainClass {
public static void main(String[] args) throws Exception {
Class.forName("forNameMethodDemo.DemoClass");
Class.forName("forNameMethodDemo.DemoClass");
Class.forName("forNameMethodDemo.DemoClass");
DemoClass demoClass = (DemoClass)Class.forName("forNameMethodDemo.DemoClass").newInstance();
}
}
公共类DemoClass {
static {
System.out.println("in Static block");
}
{
System.out.println("in Instance block");
}
}
输出将是:
in Static block
in Instance block
该in Static block
声明仅打印一次,而不打印三遍。
Class.forName()-> forName()是Class类的静态方法,它返回用于反射的Class类对象,而不是用户类对象,因此您只能像getMethods(),getConstructors()等那样调用Class类方法。
如果您只关心运行(给定运行时)类的静态块,并且仅获取类的方法,构造函数,修饰符等信息,则可以使用通过Class.forName()获得的此对象
但是,如果您要访问或调用您的类方法(在运行时给定的类),则需要具有其对象,以便Class类的newInstance方法可以为您执行此操作。它将创建该类的新实例并将其返回给您您只需将其类型转换为您的班级。
例如:假设Employee是你的班级,那么
类a = Class.forName(args [0]);
// args [0] = cmd行参数,以在运行时提供类。
员工ob1 = a.newInstance();
a.newInstance()类似于使用new Employee()创建对象。
现在,您可以访问所有类的可见字段和方法。