我正在努力理解class.forName的用法。实际上我正在研究一个项目,我有一个接受字符串的字段。类路径!我在class.forName中传递了这个字符串 - 没有异常...所以class.forName可以找到指定的类。之后我想调用指定的类。但这是我的问题。首先,我必须分离字符串才能获取类的名称......对吗?另外,如果我这样做
Class requestedClass = Class.forName(path);
AClass newClassInstance = (AClass)requestedClass.newInstance();
我有一个异常InstantiationException,因为一些参数必须在类的构造函数中传递。这有什么解决方案吗?使用if语句并调用相应的类对我来说听起来更明智,但是在很多可能的类的情况下,这种方法将是一场噩梦。谢谢!
答案 0 :(得分:3)
它很有用,因为它允许您指定要在编译代码时不存在的要加载的类。 HTML中的applet
标记使用此标记加载java.applet.Applet
的子类。 Web服务器使用它来加载Java servlet和其他Web组件。 EJB容器,Spring容器和许多其他程序使用此方法加载组件。如果您使用Eclipse或NetBeans,这些IDE使用Class.forName()
加载插件 - 这可以让他们加载每天创建的新插件。
所有这些魔力的关键是继承`。您需要能够将创建的对象视为接口或父类的实例 - 即,
Applet applet = (Applet) Class.forName(theNameOfSomeAppletClass).newInstance();
然后您可以从HTML文件中读取theNameOfSomeAppletClass
(例如)并创建该类的实例,即使您的代码从未听说过它。
大多数时候,插件API只是指定你应该为你的插件类提供一个无参数的构造函数。但是java.lang.Class
有一个getConstructors()
方法,可以让你获得Constructor
个对象,这样就可以通过将参数传递给它的构造函数来实例化一个类,如果你真的需要的话。
答案 1 :(得分:2)
您将看到的另一个重要用途是加载JDBC驱动程序。这可能是大多数java程序员遇到的Class.forName的第一次使用。你会看到的是:
Class.forName("oracle.jdbc.OracleDriver");
Connection connection = DriverManager.getConnection("jdbc:oracle:thin:...");
这里发生的是当加载OracleDriver类时(通过Class.forName),它包含类似于此的类初始化块(它可能更复杂,但说明了这一点)。该块作为类加载过程的一部分运行。
public class OracleDriver {
static {
DriverManager.registerDriver(new OracleDriver());
}
}
然后当你调用DriverManager.getConnection时,它可以询问所有已注册的驱动程序是否能够处理已经给出的url(代码更复杂,但我会稍微简化一下):
for (Driver driver : registeredDrivers) {
if (driver.acceptsURL(url)) {
// use this driver
}
}
就实例化问题而言,Class.newInstance()方法将始终调用no-arg构造函数,如果不存在则抛出异常。如果需要特定的构造函数,可以在类本身上使用“getConstructor”方法。例如,如果你想要一个带String和Long的构造函数:
Class clazz = ...; // figure out which class here
Constructor c = clazz.class.getConstructor(String.class, Long.class);
Object o = c.newInstance("foo", new Long(1L));
答案 2 :(得分:1)
正如已经指出它非常有用,因为你可以加载在编译时没有出现过的类,比如插件或扩展。
您的问题有一个简单的解决方案。简单地获取您要搜索的构造函数并提供预期的参数。 E.g:
MyClass a = (MyClass) Class.forName("com.test.MyClass")
.getConstructor(new Class[] { String.class }).newInstance("Test");
答案 3 :(得分:1)
您可以使用Class.getConstructor()
:
class Foo {
public Foo(String bar) {
System.out.println("bar = " + bar);
}
}
Class<?> fooCls = Class.forName("Foo");
Constructor<?> fooCtor = fooCls.getConstructor(String.class);
Foo foo = (Foo) fooCtor.newInstance("BAR");
如果你需要实例化的类没有no-args构造函数,并且你无法弄清楚要传递给它的参数,那你就不走运了。 (这也是你设计中的一个严重缺陷。如果一个方法需要实例化N个类中的一个,那么应该可以以相同的方式实例化所有类,无论它是构造函数签名还是工厂方法。)