据我所知,您可以使用以下构造的字符串创建一个带有参数的新类:
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
的子类实现所使用的构造函数。
有没有处理这种情况的做法?
答案 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建议,并从基类的构造函数中调用它。然后你至少知道它会被调用。
您还可以检查具有所需签名的构造函数。如果您没有找到它,则可以抛出有关该类如何不符合您的条款的异常。通过这种方式,反射可以为您提供比语言内置更多的功能。