fastcodejava
fastcodejava

Reputation: 41127

Problem with generics

I have the following statements :

    List<List<String>> myList  = new ArrayList<ArrayList<String>>();

    List<ArrayList<String>> myList  = new ArrayList<ArrayList<String>>();

The first one gives compile error. Shouldn't we code to interface? Here I am forced to code by class not the interface. Is this a generics failure, or I am understanding it wrong?

Upvotes: 0

Views: 166

Answers (5)

newacct
newacct

Reputation: 122518

You can do this: List<? extends List<String>> myList = new ArrayList<ArrayList<String>>();

The reason that your first line does not work is that you cannot do List<A> = List<B>, even if B is a subtype of A (as it is here, ArrayList is a subtype of List). Otherwise it would violate type safety. This is a basic Generics feature that many beginners have trouble with. However, you can do List<? extends A> = List<B>; in this case, the ? extends A is a wildcard that could include B. In exchange, you lose the ability to add things to a List<? extends A> (Rule: extends producer, super consumer), and this eliminates the safety problem.

Upvotes: 1

Zach L
Zach L

Reputation: 16272

The issue here is a little subtle. To make it correct, you'd want:

List<List<String>> myList = new ArrayList<List<String>>();

The definition of myList is asking for a List of Lists of Strings, but you are implementing it as an ArrayList of ArrayLists of Strings, and these don't match. This would becoming an issue if later on you tried something like:

myList.add(new LinkedList<String>());

This is ok by the definition of List of Lists of Strings, but violates the definition of the implementation. LinkedList is a List, but is not an ArrayList.

If you want to enforce that it is an ArrayList of ArrayLists of Strings, then you can use the ArrayList<ArrayList<String>> myList definition, but it's generally better to keep to interfaces.

With my revised code, you can still make it in the implementation an ArrayList of ArrayLists of Strings.

List<List<String>> myList = new ArrayList<List<String>>();
for (int i = 0; i < rowSize; i++)
{
 myList.add(new ArrayList<String>());
}

It agrees with the definition of myList as an List of Lists of Strings, but you still reap the benefits of using an ArrayList behind the scenes.

Upvotes: 1

J-16 SDiZ
J-16 SDiZ

Reputation: 26930

This is a known problem. It would have other problems if you do this.

Consider this code:

List<List<String>> myList  = new ArrayList<ArrayList<String>>();
myList.push( new LinkedList<String>() );   // impossible to catch, because java don't have generic in runtime

ArrayList<ArrayList<String>> list2 = (ArrayList<ArrayList<String>>) myList; // ok

ArrayList<String> something = list2.get(0);  // doh! impossible to assign LinkedList to ArrayList

Upvotes: 2

Mihai Toader
Mihai Toader

Reputation: 12253

The first one should be:

List<List<String>> myList  = new ArrayList<List<String>>();

The semantics are the following: the type myList is a List containg objects of type List<String>. The implementation class is an ArrayList capable of containing objects of type List<String>.

Once you want to add an object to myList you can to it like this:

myList.add(new ArrayList<String>());

Upvotes: 3

martineno
martineno

Reputation: 2635

It should be:

List<List<String>> myList = new ArrayList<List<String>>();

You need to pass in the type, which can be an interface into the ArrayList constructor. In other words you want an ArrayList which contains objects of type List<String>. Then when you are actually putting things into the list:

mList.add(new ArrayList<String>());

Upvotes: 5

Related Questions