1

Why can I not declare a List of Lists like this?

List<List<Object>> a = new ArrayList<ArrayList<Object>>();

An ArrayList is of type List so I presumed that the above code would be valid.

This is valid though:

List<ArrayList<Object>> b = new ArrayList<ArrayList<Object>>();

The inner list has to be declared as ArrayList.

Can someone explain this?

sedero
  • 55
  • 6

2 Answers2

2

You're confusing your generics. The way to do what you want is

List<List<Object>> a = new ArrayList<List<Object>>();

By using ArrayList within the generic parameter, you're narrowing the scope of the object from List to ArrayList, thereby changing the generic signature. By using ArrayList outside the generic, you're still conformant; you're specifying which implementation of List you want to use, and that the objects it will hold are of type List<Object>, exactly as the left hand side states.

To see why this is important, consider this list:

// Invalid declaration, but pretend it is valid
List<List<Object>> a = new ArrayList<ArrayList<Object>>();
a.add(new ArrayList<Object>()); // valid
a.add(new LinkedList<Object>()); // not valid because it's not an ArrayList; 
                                 // but according to the left side, it is valid!

Of course, the best method is to use Java 7's diamond operator:

List<List<Object>> a = new ArrayList<>();
Community
  • 1
  • 1
Chris Hayes
  • 11,471
  • 4
  • 32
  • 47
1

This is not as much a problem with the inner list as it is the problem of the generic parameter. As long as the generic parameter is the same (i.e. ArrayList<Object>) the initialization succeeds. Otherwise, Java does not let you make an assignment, because the compiler cannot guarantee type safety.

Imagine that this is possible:

// Let's pretend this compiles:
List<List<Object>> a = new ArrayList<ArrayList<Object>>();

Now the following must be valid:

a.add(new LinkedList<Object>());

However, this is invalid, because the object is an ArrayList of ArrayLists, so inserting a linked list into it is clearly invalid.

You can do this, however:

List<List<Object>> a = new ArrayList<List<Object>>();

This should be good enough to program to the interface.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523