65956

Generic method vs wildcard - compilation error

Question:

I had a issue where (to simplify):

public void method(List<List<?>> list){...}

gave me a compilation error when called with:

method(new ArrayList<List<String>>()); // This line gives the error

After reading a <a href="https://stackoverflow.com/a/3547372" rel="nofollow">similar thread</a>, I understood that it would work if I were to rewrite the method signature as:

public void method(List<? extends List<?>> list){...}

Now, my question is, why does the following work then?

public <T> void method(List<List<T>> list){...}

Answer1:

Confusions do come when you deal with multi-level wildcard syntax. Let's understand what those types exactly mean in there:

<ul><li>

List<List<?>> is a <em>concrete parameterized type</em>. It is a <em>heterogenous collection</em> of different types of List<E>. Since List<?> represent a family of all the instantiation of List, you can't really pass an ArrayList<List<String>> to List<List<?>>. Because, nothing stops you from adding a List<Integer> to it inside the method, and that will crash at runtime, had compiler allowed it.

</li> <li>

List<? extends List<?>> is a <em>wildcard parameterized type</em>. It represents a family of different types of List<E>. Basically, it might be a List<ArrayList<String>>, List<LinkedList<Date>>, so on. It can be a list of any type that extend from a List<?>. So, it will be safe to pass a ArrayList<List<String>> to it, the reason being, you won't be allowed to add anything, but null to the list. Adding anything to the list will be a compile time error.

</li> <li>

As for List<List<T>>, it is again a <em>concrete parameterized type</em>. And since you're dealing with a generic method now, the type parameter will be inferred to be the type that is passed for it. So, for an ArrayList<List<String>>, type T will be inferred as T. A generic method deals with the types that are declared with it. So, there is only a single type T here. All the lists you get out of List<List<T>> will certainly be a List<T> for any type T. So, it's a <em>homogenous collection</em> of that type of List. Inside the method, you can not add any arbitrary List<E> to the List<List<T>>, because the compiler doesn't know whether that type E is compatible with T or not. So, it is safe invocation.

</li> </ul><hr />

<strong>Related:</strong>

<ul><li><a href="https://stackoverflow.com/q/3546745/1679863" rel="nofollow">Multiple wildcards on a generic methods makes Java compiler (and me!) very confused</a></li> <li><a href="https://stackoverflow.com/q/19219635/1679863" rel="nofollow">Java HashMap nested generics with wildcards</a></li> <li><a href="https://stackoverflow.com/q/18194956/1679863" rel="nofollow">What are multi-level wild cards? Confusion in syntax</a></li> <li><a href="https://stackoverflow.com/q/18176594/1679863" rel="nofollow">When to use generic methods and when to use wild-card?</a></li> </ul>

Answer2:

I think I found the answer in <a href="http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html#FAQ302B" rel="nofollow">Angelika Langer's generics FAQ</a>, "Case Study #3":

<blockquote>

If a method signature uses multi-level wildcard types then there is always a difference between the generic method signature and the wildcard version of it. Here is an example. Assume there is a generic type Box and we need to declare a method that takes a list of boxes.

Example (of a method with a type parameter):

</blockquote> public static <T> void print1( List <Box<T>> list) { for (Box<T> box : list) { System.out.println(box); } } <blockquote>

Example (of method with wildcards):

</blockquote> public static void print2( List <Box<?>> list) { for (Box<?> box : list) { System.out.println(box); } } <blockquote>

Both methods are perfectly well behaved methods, but they are not equivalent. The generic version requires a homogenous list of boxes of the same type. The wildcard version accepts a heterogenous list of boxes of different type. This becomes visible when the two print methods are invoked.

</blockquote>

Answer3:

The basic reason is that List<List<?>> is not a superclass of List<List<String>>.

A List<List<?>> could contain a List<Integer> and a List<String> for example.

The generic types must match exactly, otherwise you could get erroneous assignments made.

Recommend

  • How can the java 'class' literal return different instances of the Class object for the sa
  • jQuery UI .sortable() call is slow when applies to thousands of elements
  • In BASH convert a string with . in float
  • Typescript: how to return the proper class and generic type in a dependency
  • Why have a private constructor [duplicate]
  • How to initialize global variable at each class invocation?
  • Extract text from “” HTML tag
  • Linear gradient not applying in Webkit with d3 generated SVG
  • Docker container for google cloudML on compute engine - authenticating for mounting bucket
  • How to use arithmetic operators with SAS macro variables [duplicate]
  • How to change default stop edit behavior in jtable
  • Netlink sockets and libnl - nl_recvmsgs_default returning -16 (EBUSY)
  • Is there a way to link a linux's thread TID and a pthread_t “thread ID”
  • c++ using primitive types as a base class
  • What is this strange character in chrome's resource css viewer?
  • How to concat Pandas dataframe columns
  • Using same constraints in multiple classes
  • Where these are stored?
  • Time out Error in send mail
  • C#: Import/Export Settings into/from a File
  • abstracting over a collection
  • JSR-330 support in Picocontainer : @Inject … @Named(\"xxx)
  • How can I tell a form not to dispose a particular control when it closes?
  • Creating a DropDownList
  • Who propagate bugfixes across branches (corporate development)?
  • Cast between interfaces whose interface signatures are same
  • How do I include a SWC in an AS2 Flash project?
  • How to add a focus style to an editable ComboBox in WPF
  • Z3: Convert between FP and BitVector?
  • How do I superscript characters in a UIButton?
  • Date Conversion from yyyy-mm-dd to dd-mm-yyyy
  • C++ Partial template specialization - design simplification
  • Scrapy recursive link crawler
  • Javascript simulate pressing enter in input box
  • Is my CUDA kernel really runs on device or is being mistekenly executed by host in emulation?
  • Counter field in MS Access, how to generate?
  • Convert array of 8 bytes to signed long in C++
  • Comma separated Values
  • retrieve vertices with no linked edge in arangodb
  • How can I get HTML syntax highlighting in my editor for CakePHP?