Using generic type to create instance instead of reflection in java

245 views Asked by At

I have code that looks like follows:

public class Person{
    private Configuration configuration;
    public void act(){
        final Action action = new Factory().createAction(configuration);
        ....
    }
}

public class Factory{
    public Action createAction(Configuration configuration){
        Constructor<? extends Action> constructor =
                  configuration.getActionClass.
                  getConstructor(configuration.getClass());
        return constructor.newInstance(configuration);
    }
}

public class Configuration{
    private Class<? extends Action> actionClass;

    public void setActionClass(Class<? extend Action> cls){
        this.actionClass = cls;
    }

    public Class<? extends Action> getActionClass(){
        return this.actionClass;
    }
}

Each time act() is called, a new Action instance is created for some reason. I need to subclass Action and pass it to act().

So I use reflection on a factory method to achieve that. But it seems overkill and not type safe.

Is it possible to repalce reflection with a type safe method such like generics?

2

There are 2 answers

5
ᴘᴀɴᴀʏɪᴏᴛɪs On BEST ANSWER

Due to type erasure (see #1) you can't avoid reflection and Class<?> arguments if you want to instantiate a type at runtime, so to answer your question it may be an overkill but new T(); just isn't possible.

You could make it type safe however, by adding a generic type parameter to your Configuration class.

public class Configuration<T extends Action> {
    private Class<T> actionClass;

    public void setActionClass(Class<T> cls){
        this.actionClass = cls;
    }

    public Class<T> getActionClass(){
        return this.actionClass;
    }
}

And get rid of any raw references to it. (ie. switch Configuration to Configuration<T> wherever it's being used)

0
bresai On

I got a very neat solution using new Function feature of Java 8 from a friend.

public class Person{
    private Configuration configuration;
    public void act(){
        final Action action = configuration.getActionFactory().apply(configuration);
        ....
    }
}

public class Configuration{
    private Function<Configuration, Action> actionFactory = Action::new;

    public void setActionFactory(Function<Configuration, Action> actionFactory){
        this.actionFactory = actionFactory;
    }

    public Function<Configuration, Action> actionFactory getActionFactory(){
        return this.actionFactory;
    }
}