I have the following statements :
List<List<String>> myList = ne开发者_开发技巧w 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?
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>());
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>());
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
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.
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.
精彩评论