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