Shvalb
Shvalb

Reputation: 1933

Adding generic types to EnumMap

I'm trying to add instances to the following EnumMap:

class ActiveG<D extends GData, T extends GTemplate> {

    EnumMap<GStateType, GState<ActiveG<D,T>> map;
    ..
    ..
}

class TGData extends GData {...}
class TGTemplate extends GTemplate {....}

class ActiveTG extends ActiveG<TGData, TGTemplate> {

    // fails with compilation error
    super.states.put(GStateType.WAITING, new TGWaitingState<ActiveTG>(this));
    ...
    ...
}

The error I get:

The method put(GStateType, GState<ActiveG<TGData,TGTemplate>>) in the
type EnumMap<GStateType,GState<ActiveG<TGData,TGTemplate>>> is not 
applicable for the arguments (GStateType, TGWaitingState<ActiveTG>)

Can anyone try to help me figure out what's missing to make it work?? Thanks!

Upvotes: 0

Views: 266

Answers (1)

Adrian Shum
Adrian Shum

Reputation: 40036

In brief, Generics in Java is not covariance.

e.g. if you have

class Parent {...}

class Child extends Parent {...}

Foo<Child> is NOT a Foo<Parent>

Go back to your code:

your enum map in ActiveTG is expecting GState<ActiveG<TGData,TGTemplate>> as value, but you are giving it a TGWaitingState<ActiveTG>, which is a GState<ActiveTG>.

Although ActiveTG is-a ActiveG<TGData,TGTemplate>, GState<ActiveTG> is NOT a GState<ActiveG<TGData,TGTemplate>>.

In order to solve it, you will need quite some change in the type params, like

class ActiveG<D extends GData, 
              T extends GTemplate, 
              E extends ActiveG<D,T>> {
     EnumMap<GStateType, GState<E>> map;
}

or simply make map with type EnumMap<GStateType, GState<? extends ActiveG<D,T>>. This may not work very well in some situation, for example, you need to retrieve the result as a GState<ActiveTG> instead of GState<ActiveG<D,T>>

Upvotes: 1

Related Questions