Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p><em>Multi-level wildcards</em> can be a bit tricky at times, when not dealt with properly. You should first learn how to read a multi-level wildcards. Then you would need to learn to interpret the meaning of <code>extends</code> and <code>super</code> bounds in multi-level wildcards. Those are important concepts that you must first learn before starting to use them, else you might very soon go mad.</p> <p><strong>Interpreting a multi-level wildcard:</strong></p> <p>**Multi-level wildcards* should be read top-down. First read the outermost type. If that is yet again a paramaterized type, go deep inside the type of that parameterized type. The understanding of the meaning of <em>concrete parameterized type</em> and <em>wildcard parameterized type</em> plays a key role in understand how to use them. For example:</p> <pre><code>List&lt;? extends Number&gt; list; // this is wildcard parameterized type List&lt;Number&gt; list2; // this is concrete parameterized type of non-generic type List&lt;List&lt;? extends Number&gt;&gt; list3; // this is *concrete paramterized type* of a *wildcard parameterized type*. List&lt;? extends List&lt;Number&gt;&gt; list4; // this is *wildcard parameterized type* </code></pre> <p>First 2 are pretty clear. </p> <p>Take a look at the 3rd one. How would you interpret that declaration? Just think, what type of elements can go inside that list. All the elements that are capture-convertible to <code>List&lt;? extends Number&gt;</code>, can go inside the outer list:</p> <ul> <li><code>List&lt;Number&gt;</code> - Yes</li> <li><code>List&lt;Integer&gt;</code> - Yes</li> <li><code>List&lt;Double&gt;</code> - Yes</li> <li><code>List&lt;String&gt;</code> - <strong>NO</strong></li> </ul> <p><strong>References:</strong></p> <ul> <li><a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.10" rel="noreferrer">JLS §5.1.10 - Capture Conversion</a></li> <li><a href="http://www.angelikalanger.com/GenericsFAQ/FAQSections/TechnicalDetails.html" rel="noreferrer">Java Generics FAQs - Angelika Langer</a> <ul> <li><a href="http://www.angelikalanger.com/GenericsFAQ/FAQSections/TechnicalDetails.html#Wildcard%20Capture" rel="noreferrer">Wildcard Capture</a></li> </ul></li> <li><a href="http://www.ibm.com/developerworks/java/library/j-jtp04298/index.html" rel="noreferrer">IBM Developer Works Article - Understanding Wildcard Captures</a></li> </ul> <p>Given that the 3<sup>rd</sup> instantiation of list can hold the above mentioned type of element, it would be wrong to assign the reference to a list like this:</p> <pre><code>List&lt;List&lt;? extends Number&gt;&gt; list = new ArrayList&lt;List&lt;Integer&gt;&gt;(); // Wrong </code></pre> <p>The above assignment should not work, else you might then do something like this:</p> <pre><code>list.add(new ArrayList&lt;Float&gt;()); // You can add an `ArrayList&lt;Float&gt;` right? </code></pre> <p>So, what happened? You just added an <code>ArrayList&lt;Float&gt;</code> to a collection, which was supposed to hold a <code>List&lt;Integer&gt;</code> only. That will certainly give you trouble at runtime. That is why it's not allowed, and compiler prevents this at compile time only.</p> <p>However, consider the 4<sup>th</sup> instantiation of multi-level wildcard. That list represents a family of all instantiation of <code>List</code> with type parameters that are subclass of <code>List&lt;Number&gt;</code>. So, following assignments are valid for such lists:</p> <pre><code>list4 = new ArrayList&lt;Integer&gt;(); list4 = new ArrayList&lt;Double&gt;(); </code></pre> <p><strong>References:</strong></p> <ul> <li><a href="http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeArguments.html#What%20do%20multilevel%20wildcards%20mean?" rel="noreferrer">What do multi-level wildcards mean?</a></li> <li><a href="http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html#What%20is%20the%20difference%20between%20various%20multi-level%20instantiations?" rel="noreferrer">Difference between a <code>Collection&lt;Pair&lt;String,Object&gt;&gt;</code>, a <code>Collection&lt;Pair&lt;String,?&gt;&gt;</code> and a <code>Collection&lt;? extends Pair&lt;String,?&gt;&gt;</code>?</a></li> </ul> <hr /> <p><strong>Relating to single-level wildcard:</strong></p> <p>Now this might be making a clear picture in your mind, which relates back to the invariance of generics. A <code>List&lt;Number&gt;</code> is not a <code>List&lt;Double&gt;</code>, although <code>Number</code> is superclass of <code>Double</code>. Similarly, a <code>List&lt;List&lt;? extends Number&gt;&gt;</code> is not a <code>List&lt;List&lt;Integer&gt;&gt;</code> even though the <code>List&lt;? extends Number&gt;</code> is a superclass of <code>List&lt;Integer&gt;</code>.</p> <p><strong>Coming to the concrete problem:</strong></p> <p>You have declared your map as:</p> <pre><code>HashMap&lt;String, Hashmap&lt;String, HashSet&lt;? extends AttackCard&gt;&gt;&gt; superMap; </code></pre> <p><sub>Note that there is <strong>3-level of nesting</strong> in that declaration. <strong>Be careful</strong>. It's similar to <code>List&lt;List&lt;List&lt;? extends Number&gt;&gt;&gt;</code>, which is different from <code>List&lt;List&lt;? extends Number&gt;&gt;</code>.</sub></p> <p>Now what all element type you can add to the <code>superMap</code>? Surely, you can't add a <code>HashMap&lt;String, HashSet&lt;Assassin&gt;&gt;</code> into the <code>superMap</code>. Why? Because we can't do something like this:</p> <pre><code>HashMap&lt;String, HashSet&lt;? extends AttackCard&gt;&gt; map = new HashMap&lt;String, HashSet&lt;Assassin&gt;&gt;(); // This isn't valid </code></pre> <p>You can only assign a <code>HashMap&lt;String, HashSet&lt;? extends AttackCard&gt;&gt;</code> to <code>map</code> and thus only put that type of map as value in <code>superMap</code>. </p> <p><strong>Option 1:</strong></p> <p>So, one option is to modify your last part of the code in <code>Assassin</code> class(I guess it is) to:</p> <pre><code>private HashMap&lt;String, HashSet&lt;? extends AttackCard&gt;&gt; pool = new HashMap&lt;&gt;(); public HashMap&lt;String, HashSet&lt;? extends AttackCard&gt;&gt; get() { return pool; } </code></pre> <p>... and all will work fine.</p> <p><strong>Option 2:</strong></p> <p>Another option is to change the declaration of <code>superMap</code> to:</p> <pre><code>private HashMap&lt;String, HashMap&lt;String, ? extends HashSet&lt;? extends AttackCard&gt;&gt;&gt; superMap = new HashMap&lt;&gt;(); </code></pre> <p>Now, you would be able to put a <code>HashMap&lt;String, HashSet&lt;Assassin&gt;&gt;</code> to the <code>superMap</code>. How? Think of it. <code>HashMap&lt;String, HashSet&lt;Assassin&gt;&gt;</code> is capture-convertible to <code>HashMap&lt;String, ? extends HashSet&lt;? extends AttackCard&gt;&gt;</code>. Right? So the following assignment for the inner map is valid:</p> <pre><code>HashMap&lt;String, ? extends HashSet&lt;? extends AttackCard&gt;&gt; map = new HashMap&lt;String, HashSet&lt;Assassin&gt;&gt;(); </code></pre> <p>And hence you can put a <code>HashMap&lt;String, HashSet&lt;Assassin&gt;&gt;</code> in the above declared <code>superMap</code>. And then your original method in <code>Assassin</code> class would work fine.</p> <hr /> <p><strong>Bonus Point:</strong></p> <p>After solving the current issue, you should also consider to change all the concrete class type reference to their respective super interfaces. You should change the declaration of <code>superMap</code> to:</p> <pre><code>Map&lt;String, Map&lt;String, ? extends Set&lt;? extends AttackCard&gt;&gt;&gt; superMap; </code></pre> <p>So that you can assign either <code>HashMap</code> or <code>TreeMap</code> or <code>LinkedHashMap</code>, anytype to the <code>superMap</code>. Also, you would be able to add a <code>HashMap</code> or <code>TreeMap</code> as values of the <code>superMap</code>. It's really important to understand the usage of <a href="http://en.wikipedia.org/wiki/Liskov_substitution_principle" rel="noreferrer">Liskov Substitution Principle</a>.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload