为什么class.forName很有用

时间:2012-07-04 22:11:44

标签: java

我正在努力理解class.forName的用法。实际上我正在研究一个项目,我有一个接受字符串的字段。类路径!我在class.forName中传递了这个字符串 - 没有异常...所以class.forName可以找到指定的类。之后我想调用指定的类。但这是我的问题。首先,我必须分离字符串才能获取类的名称......对吗?另外,如果我这样做 Class requestedClass = Class.forName(path); AClass newClassInstance = (AClass)requestedClass.newInstance();
我有一个异常InstantiationException,因为一些参数必须在类的构造函数中传递。这有什么解决方案吗?使用if语句并调用相应的类对我来说听起来更明智,但是在很多可能的类的情况下,这种方法将是一场噩梦。谢谢!

4 个答案:

答案 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个类中的一个,那么应该可以以相同的方式实例化所有类,无论它是构造函数签名还是工厂方法。)

相关问题