1

I have a variable e4 of type List<List<Integer>>, which I'd like to initialise with a new ArrayList<ArrayList<Integer>>(). I expect this would work, in a similar way to how it's possible to assign to a List<Integer>-type variable a new ArrayList<Integer>(). Instead there is a compile error; what is the reasoning behind this, and is it necessary then to use a statement such as e3 or e5?

import java.util.List;
import java.util.ArrayList;

public class Example {
    public static void main(String[] args) {
        // e1-3 compile as expected
        ArrayList<Integer> e1 = new ArrayList<Integer>();
        List<Integer> e2 = new ArrayList<Integer>();
        ArrayList<ArrayList<Integer>> e3 = new ArrayList<ArrayList<Integer>>();
        // e4 does not compile
        List<List<Integer>> e4 = new ArrayList<ArrayList<Integer>>();
        // e5 does compile
        List<ArrayList<Integer>> e5 = new ArrayList<ArrayList<Integer>>();
    }
}

Upon trying to compile the above, I get the error message:

/home/james/Example.java:12: error: incompatible types
        List<List<Integer>>           e4 = new ArrayList<ArrayList<Integer>>();
                                           ^
required: List<List<Integer>>
found:    ArrayList<ArrayList<Integer>>
1 error
Suzon
  • 749
  • 1
  • 8
  • 21
James Hiew
  • 6,040
  • 5
  • 27
  • 41

4 Answers4

4

The reason is that an List<ArrayList<Integer>> is not a List<List<Integer>>, even though an ArrayList<Integer> is a List<Integer>. The reasoning here is the same as the fact that List<Dog> is not a List<Animal>, even though a Dog is an Animal. The analogy is that ArrayList<Integer> is to List<Integer> as Dog is to Animal.

The following are alternatives:

1) Your "e5", which matches the generic type exactly.

List<ArrayList<Integer>>      e5 = new ArrayList<ArrayList<Integer>>();

or

List<List<Integer>> e5 = new ArrayList<List<Integer>>();

2) Using a wildcard:

List<? extends List<Integer>>      e6 = new ArrayList<ArrayList<Integer>>();
rgettman
  • 176,041
  • 30
  • 275
  • 357
0

The way java Works

List<List<Integer>> list = new ArrayList<ArrayList<Integer>>

will not work because the internal ArrayList doesn't match up with the type of List. It is looking for exactly a List.

You want the following

List<? extends List<Integer>> list = new ArrayList<ArrayList<Integer>>();
0

The reason is, generics in Java are invariant. Let's see a very simple example first:

// This doesn't compile
List<Number> list = new ArrayList<Integer>();

The above assignment won't compile because an ArrayList<Integer> is not a subtype of List<Number>, even though Integer is subtype of Number.

Using that concept to nested generics:

// This also shouldn't compile
List<List<Integer>> list = new ArrayList<ArrayList<Integer>>();

Although ArrayList<Integer> is a subtype of List<Integer>, that doesn't make ArrayList<ArrayList<Integer>> a subtype of List<List<Integer>>. So it doesn't compile.

To make it compile, you can use bounded wildcards there:

// This would work now.
List<? extends List<Integer>> list = new ArrayList<ArrayList<Integer>>();
Rohit Jain
  • 209,639
  • 45
  • 409
  • 525
0
Whenever you are specifying ;

List<List<Integer>> e4 = new ArrayList<ArrayList<Intger>>();

This stands out to be wrong because when you are creating the ArrayList (Implementation of the List) e4 you are specifying that it can contain List (all kinds of implementation of lists) of Integer but while instantiating it you are strictly specifying it as ArrayList of Integer which is contradicting with your declaration.

Moreover Polymorphism only applies to the base type (Base type means the collection class itself.)

Your example can be correlated with another example : 

List<Number> l1= new ArrayList<Integer>(); /*This will never compile though Integer is a subclass of Number as we are not only changing the base type but also the generic type which is wrong.*/

But this will definitely compile 

List<Number> l2 =new ArrayList<Number>(); //Changed only the base type.


For better understanding read Sun Certified Programmer for Java 6 by Kathy Sierra and Bert Bates.