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: comiler 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> - yes
  • list<integer> - yes
  • list<double> - yes
  • list<string> - no

references:

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:


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

Popular posts from this blog

java.util.scanner - How to read and add only numbers to array from a text file -

rewrite - Trouble with Wordpress multiple custom querystrings -

php - Accessing static methods using newly created $obj or using class Name -