简体   繁体   中英

Java Instantiate Generic Type

I have a class that takes in two parameterized types and I want to have a method that returns a new instance of one of the types. This is the class:

public class StateMachine<S extends State, E extends StateObject> {

    // State
    protected ArrayMap<S, E> states;
    protected E currentState;
    protected Entity entity;

    // Bits
    private Builder builder = new Builder();
    private int bitOffset;
    private boolean firstState = false;

    public StateMachine(Entity entity) {
        this.entity = entity;
        states = new ArrayMap<S, E>();
    }

    public E createState(S key) {
        // State identifiers must also be taggable
        assert (key instanceof Tag);
        if (!firstState) {
            firstState = true;
            bitOffset = key.numStates();
        }
        E state = (E) new StateObject(entity);
        state.bitOffset = bitOffset;
        state.bits.set(((Tag) key).getIndex());
        states.put(key, state);
        return state;
    }

    // Remainder omitted....

}

As you can see, I want to create a state and return its value based on the parameterized type. Currently, I have an EntityState class that extends StateObject and have an EntityStateMachine that extends StateMachine with the parameters <StateIdentifier, EntityState> . However, when I call createState from the EntityStateMachine , the returned value is not an EntityState but rather a StateObject .

How can I ensure that the returned value is casted to proper parameterized type?

Java pattern to deal with this is to store Class<E> , and use its newInstance method, as follows:

// Class<E> object will be used to create new instances
private final Class<E> stateClass;
// Users will pass the class to StateMachine's constructor
public StateMachine(Entity entity, Class<E> stateClass) {
    this.entity = entity;
    this.stateClass = stateClass;
    states = new ArrayMap<S, E>();
}

Now you can create new state objects as follows:

E state = stateClass.newInstance(); // Only parameterless constructors are supported
state.setEntity(entity);

How can I ensure that the returned value is casted to proper parameterized type?

This is not the question you should ask. The real question is,

How can I create an instance of a type parameter?

And the answer, of course is, "no way". You need a workaround, these are some ideas:

  1. Pass an instance of Class<YourType> so the instance can be created reflectively.
  2. Pass a factory of objects of YourType .
  3. Pass an instance of YourType , define a method like newInstance on it and use it as a factory of more objects of the same type.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM