Java HashMap nested generics with wildcards -
i'm trying make hashmap of hashmap values containing hashsets of different subclasses of custom class, so:
hashmap<string, hashmap<string, hashset<? extends attackcard>>> supermap
attackcard
has subclasses such as: mage
, assassin
, fighter
. each hashmap in supermap ever have hashsets containing single subclass of attackcard
.
when try putting a
hashmap<string, hashset<assassin>>
into supermap, compiler error:
below code error occurs:
public class cardpool { private hashmap<string, hashmap<string, hashset<? extends attackcard>>> attackpool = new hashmap<>(); private arraylist<auxiliarycard> auxiliarypool; public cardpool() { (line 24)this.attackpool.put("assassins", new assassinpool().get()); /* this.attackpool.put("fighters", new fighter().getpool()); this.attackpool.put("mages", new mage().getpool()); this.attackpool.put("marksmen", new marksman().getpool()); this.attackpool.put("supports", new support().getpool()); this.attackpool.put("tanks", new tank().getpool()); */ this.auxiliarypool = new arraylist<>(new auxiliarycard().getpool()); }
and here snippet of assassinpool get-method:
private hashmap<string, hashset<assassin>> pool = new hashmap<>(); public hashmap<string, hashset<assassin>> get() { return pool; }
i'd comment solve problem , have wonderfully working program making attackcardpools, such assassinpool, return , contain hashsets of attackcard instead of respective subclass. i'm trying understand compilation error, :)
compilation error @ line 24: error: no suitable method found `put(string, hashmap<string,hashset<assassin>>>` this.attackpool.put("assassins", new assassinpool(). get()); method hashmap.putp.(string, hashmap<string,hashset<? extends attackcard>>>` not applicable (actual argument `hashmap<string, hashset<assassin>>` cannot converted `hashmap<string, hashset<? extends attackcard>>` method invocation conversion)
multi-level wildcards can bit tricky @ times, when not dealt properly. should first learn how read multi-level wildcards. need learn interpret meaning of extends
, super
bounds in multi-level wildcards. important concepts must first learn before starting use them, else might go mad.
interpreting multi-level wildcard:
**multi-level wildcards* should read top-down. first read outermost type. if yet again paramaterized type, go deep inside type of parameterized type. understanding of meaning of concrete parameterized type , wildcard parameterized type plays key role in understand how use them. example:
list<? extends number> list; // wildcard parameterized type list<number> list2; // concrete parameterized type of non-generic type list<list<? extends number>> list3; // *concrete paramterized type* of *wildcard parameterized type*. list<? extends list<number>> list4; // *wildcard parameterized type*
first 2 pretty clear.
take @ 3rd one. how interpret declaration? think, type of elements can go inside list. elements capture-convertible list<? extends number>
, can go inside outer list:
list<number>
- yeslist<integer>
- yeslist<double>
- yeslist<string>
- no
references:
- jls §5.1.10 - capture conversion
- java generics faqs - angelika langer
- ibm developer works article - understanding wildcard captures
given 3rd instantiation of list can hold above mentioned type of element, wrong assign reference list this:
list<list<? extends number>> list = new arraylist<list<integer>>(); // wrong
the above assignment should not work, else might this:
list.add(new arraylist<float>()); // can add `arraylist<float>` right?
so, happened? added arraylist<float>
collection, supposed hold list<integer>
only. give trouble @ runtime. why it's not allowed, , compiler prevents @ compile time only.
however, consider 4th instantiation of multi-level wildcard. list represents family of instantiation of list
type parameters subclass of list<number>
. so, following assignments valid such lists:
list4 = new arraylist<integer>(); list4 = new arraylist<double>();
references:
- what multi-level wildcards mean?
- difference between
collection<pair<string,object>>
,collection<pair<string,?>>
,collection<? extends pair<string,?>>
?
relating single-level wildcard:
now might making clear picture in mind, relates invariance of generics. list<number>
not list<double>
, although number
superclass of double
. similarly, list<list<? extends number>>
not list<list<integer>>
though list<? extends number>
superclass of list<integer>
.
coming concrete problem:
you have declared map as:
hashmap<string, hashmap<string, hashset<? extends attackcard>>> supermap;
note there 3-level of nesting in declaration. be careful. it's similar list<list<list<? extends number>>>
, different list<list<? extends number>>
.
now element type can add supermap
? surely, can't add hashmap<string, hashset<assassin>>
supermap
. why? because can't this:
hashmap<string, hashset<? extends attackcard>> map = new hashmap<string, hashset<assassin>>(); // isn't valid
you can assign hashmap<string, hashset<? extends attackcard>>
map
, put type of map value in supermap
.
option 1:
so, 1 option modify last part of code in assassin
class(i guess is) to:
private hashmap<string, hashset<? extends attackcard>> pool = new hashmap<>(); public hashmap<string, hashset<? extends attackcard>> get() { return pool; }
... , work fine.
option 2:
another option change declaration of supermap
to:
private hashmap<string, hashmap<string, ? extends hashset<? extends attackcard>>> supermap = new hashmap<>();
now, able put hashmap<string, hashset<assassin>>
supermap
. how? think of it. hashmap<string, hashset<assassin>>
capture-convertible hashmap<string, ? extends hashset<? extends attackcard>>
. right? following assignment inner map valid:
hashmap<string, ? extends hashset<? extends attackcard>> map = new hashmap<string, hashset<assassin>>();
and hence can put hashmap<string, hashset<assassin>>
in above declared supermap
. , original method in assassin
class work fine.
bonus point:
after solving current issue, should consider change concrete class type reference respective super interfaces. should change declaration of supermap
to:
map<string, map<string, ? extends set<? extends attackcard>>> supermap;
so can assign either hashmap
or treemap
or linkedhashmap
, anytype supermap
. also, able add hashmap
or treemap
values of supermap
. it's important understand usage of liskov substitution principle.
Comments
Post a Comment