如何使用新实例创建需要参数的类?

时间:2010-01-20 01:19:22

标签: java reflection

据我所知,您可以使用以下构造的字符串创建一个带有参数的新类:

Class<? extends Base> newClass = (Class<? extends Base>)Class.forName(className);
Constructor<? extends Base> c = newClass.getConstructor(new Class[] {Manager.class, Integer.TYPE});
Base a = c.newInstance(new Object[] {this, new Integer(0)});

但我不相信有一种方法可以确保Base的子类实现所使用的构造函数。

有没有处理这种情况的做法?

4 个答案:

答案 0 :(得分:2)

无法通过子类强制执行特定构造函数。 如果您是Base类的作者,则可以声明某种init(Manager, int)方法,而不是使用带参数的构造函数。

答案 1 :(得分:2)

如果参数是固定的,并且您想使用newInstance,那么您将面临一个问题,即您无法强制在子类中存在匹配的构造函数。如果您希望能够让编译器对此进行检查,您可以使用工厂类介于两者之间:使用您想要的参数定义具有createInstance的工厂接口,而不是直接注册子类,注册生产它的工厂:

Class<? extends BaseFactory> newClass = 
      (Class<? extends BaseFactory>)Class.forName(factoryClassNameName);
BaseFactory factory = newClass.getInstance();
Base a = factory.createInstance(this, 0);  // no reflection necessary here

如果您需要从配置字符串创建对象实例,并且事情可能比具有固定数量的参数的简单newInstance调用更复杂,您应该查看DI容器。所有这些都允许您以多种非常灵活的方式创建实例,包括使用复杂对象本身的参数(您会发现很难用扁平字符串编码)。

中间地带正在使用属性来配置实例。查看日志框架如何使用属性文件配置各种组件。

答案 2 :(得分:2)

@axtavt是对的。您不能强制子类为构造函数提供特定签名。 (在非反射的情况下,没有意义,因为Java构造函数不是多态的。反射总是有点......丑陋。)

如果您想要一种创建多态对象的方法,可以使用Factory模式。

public interface BaseFactory {
    Base create(int arg1, String arg2);
    Base create(int arg1, float arg2);
}

public class Foo implements Base { .... }

public class FooFactory implements BaseFactory {
    public Base create(int arg1, String arg2) {
        return new Foo(arg1, arg2);
    }
    public Base create(int arg1, float arg2) {
        return new Foo(arg1, Float.toString(arg2));
    }
}

唯一的麻烦是工厂方法的返回类型将是基本类型。因此,通常使用工厂方法将需要将创建的对象强制转换为期望的子类型。你可以通过使用泛型来避免这种情况......

从好的方面来说,使用Factory可能会让你避免首先使用反射。即使没有,您也可以反复调用工厂方法,并保证如果工厂实现工厂接口, 将为方法提供预期的签名。

答案 3 :(得分:1)

构造函数与常规方法不同:您不能声明子项必须实现的抽象构造函数。换句话说,您无法强制如何实例化子类。在OO哲学中,这不属于基类的职责范围。

如果需要,可以创建一个抽象初始化方法,如axtavt建议,并从基类的构造函数中调用它。然后你至少知道它会被调用。

您还可以检查具有所需签名的构造函数。如果您没有找到它,则可以抛出有关该类如何不符合您的条款的异常。通过这种方式,反射可以为您提供比语言内置更多的功能。