Paulo
Paulo

Reputation: 3008

Using reflection to create an instance based on getClass of generic class

I would like to know what is the right way to declare Class<...> stateBaseClass, when my goal is to create an instance by using Reflection: state = stateBaseClass.newInstance(); without using cast.

I put some comments in the code below:

abstract class StateBase{} // It is so complex to be serializable.

class State extends StateBase{}

class StateInstanceDescription <T extends StateBase> implements Serializable{ 
    private static final long serialVersionUID = -828114417567233018L;

    transient private T stateBase;

    // what is the right way to declare the line below to void that cast?
    private Class<? extends StateBase> stateBaseClass; 

    public StateInstanceDescription(T base){
        this.stateBase = base;
        stateBaseClass = base.getClass();
    }

    public T getBase() {
        return stateBase;
    }

    public Class<? extends StateBase> getBaseClass() {
        return stateBaseClass;
    }

}

public class Main {
    public static void main(String ... args) throws InstantiationException, IllegalAccessException{
        State state = new State();
        StateInstanceDescription<State> stateInstDesc = new StateInstanceDescription<>(state);

        // ... At some point, I will recreate State after deserialize stateInstDesc.
        // compiler-time error. Compiler is asking for casting it to (State). 
        // There is a way to avoid this cast?
        state = stateInstDesc.getBaseClass().newInstance(); 
    }
}

Upvotes: 0

Views: 63

Answers (1)

Luiggi Mendoza
Luiggi Mendoza

Reputation: 85779

getBaseClass() returns a Class<? extends StateBase> so the result of newInstace can be any subclass of StateBase (depending on the class returned). The compiler cannot be sure that this result is specifically of type State or from another subclass.

To fix this, work with Class<T> and pass this as argument to the constructor of StateInstanceDescription:

class StateInstanceDescription <T extends StateBase> implements Serializable { 

    transient private T stateBase;

    private Class<T> stateBaseClass; 

    public StateInstanceDescription(T base, Class<T> clazzBase) {
        this.stateBase = base;
        stateBaseClass = clazzBase;
    }

    public T getBase() {
        return stateBase;
    }

    public Class<T> getBaseClass() {
        return stateBaseClass;
    }
}

Then in main:

State state = new State();
StateInstanceDescription<State> stateInstDesc = new StateInstanceDescription<>(state, State.class);

state = stateInstDesc.getBaseClass().newInstance(); 

Upvotes: 3

Related Questions