开发者

How to use new instance to create a class that requires parameters?

I understand that you can create a new class with parameters from a string with the following construct:

C开发者_运维知识库lass<? 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)});

But I don't believe there to be a way to ensure subclasses of Base implements the constructor used.

Is there any practice to handling this situation?


There is no way to enforce implementation of a particular constructor by subclasses. If you are author of the Base class, you can declare some kind of init(Manager, int) method instead of using constructor with parameters.


If the parameters are fixed, and you want to use newInstance, you are left with the problem that you cannot enforce the existence of a matching constructor in a subclass. If you want to be able to have the compiler check for this, you can use a factory class to go in between: Define a factory interface that has createInstance with the parameters you want, and instead of registering the subclass directly, register the factory that produces it:

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

If you need to create object instances from configuration strings, and things can get more complicated than a simple newInstance call with a fixed number of parameters can handle, you should look at DI containers. All of those allow you to create instances in a number of very flexible ways, including using parameters that are complex objects themselves (which you would find hard to encode in a flat string).

A middle-ground is using properties to configure the instances. Look for example how the logging frameworks configure the various components using a properties file.


@axtavt is right. You cannot force a subclass to provide constructors with particular signatures. (In the non-reflective case there is no point because Java constructors are not polymorphic. And reflection is always a bit ... ugly.)

If you want a way to create objects that is polymorphic, you could use the Factory pattern.

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));
    }
}

The only hassle is that the return type of the factory method will be the base type. Hence a typically use of the factory method will need to cast the created object to the expected subtype. You can probably avoid this by using generics ...

On the plus side, using the Factory may allow you to avoid using reflection in the first place. And even if not, you can call the factory methods reflectively with the assurance that if the factory implements the factory interface, it will provide methods with the expected signatures.


Constructors are not like regular methods: You can't declare an abstract constructor that a child has to implement. In other words, you don't get to mandate how a child class may be instantiated. In OO philosophy, that's not within the base class's responsibilities.

If you want, you can create an abstract initializing method, like axtavt suggested, and call it from your base class's constructor. Then you at least know that it will get called.

You can also check for a constructor with the signature you want. If you don't find it, you can throw an Exception about how the class doesn't conform to your terms. In this way, reflection can give you a little more power than is built into the language.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜