views:

164

answers:

4

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

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

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?

+2  A: 

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.

axtavt
+1. However, if the subclass needs additional parameters to initialize, you have the same problem.
Thilo
Thanks - that was something I considered - but I dismissed this as the subclasses will be unable to take advantage of final attributes.
Pool
@Thilo - I'm not worried about that scenario - I would like to enforce that subclasses can't have additional or different parameters.
Pool
+2  A: 

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.

Thilo
+1  A: 

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.

Kevin Conner
Great, thanks - that last sentence is interesting.
Pool
+2  A: 

@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.

Stephen C
+1 "The only hassle is that the return type of the factory method will be the base type." That should be okay. In the question, he also just assigns to Base.
Thilo
Interesting. I would prefer to avoid reflection but I can't really use a factory as not all the possible classes are necessarily available at run time.
Pool
@The Feast: You would still use reflection to load the factory. If not all required classes are available at run time, any approach to load it will fail.
Thilo
@Feast - you can use reflection to obtain the relevant factory class and instantiate it. From then on, creation of objects can be done without reflection.
Stephen C