From the java generics tutorial:


List<String>[] lsa = new List<String>[10]; // not really allowed

String s = lsa[1].get(0); // run-time error - ClassCastException

If arrays of parameterized type were allowed, the example above would compile without any unchecked warnings, and yet fail at run-time."

I have problem understanding why would there be a ClassCastException, because if it were a valid syntax then the individual elements would be of a list of type List<String> and then each element of that can be accessed without any problem.


List<String> list = new ArrayList<String>();
String s = list.get(0);

is allowed so what would be the problem if in the case individual array element was a list type?

Because Generics is acheived through Erasure (google "java generics erasure" to find out more about this).

Simply do List<String>[] a = (List<String>[]) new List[5]; It will give you a warning about an unchecked cast, but it works. You will be able to retreive elements from the array as List<String>'s without having to cast them at that time. I.E. List<String> b = a[0]; , rather than List<String> b = (List<String>) a[0]; . And String s = a[0].get(0); also "works". And, the following will result in compiler errors a[1] = new List<Integer>(); . You just simply can't do new List<String>[] due to the restrictions of erasure.

"Similar to Upper Bounds, we have Lower Bounds with the following syntax,

List<? super Dog> dogs = new ArrayList<Dog>();

This declaration tells that along with Dog type, all other sub-types of Dog is also allowed. Not any of the super-type of Dog can be added including java.lang.Object. So, if we have classes like GoodDog and BadDog, both extending the Dog class, then the following statements are legal.

dogs.add(new Dog());
dogs.add(new GoodDog());
dogs.add(new BadDog());"

From the above discussion it seems very much like:
The solution to this situation is the usage of wild-cards along with parametric bounding. Have a look over the following declaration.

List<? extends Animal> animals = new ArrayList<Animal>();

It tells that a list is being declared with type being anything (?) that is extending the Animal class. Though it looks very similar to the above declaration it has some differences. The first thing is that it is now possible for the animals reference to point to a list that is holding any sub-type of Animal objects.

List<Dog> dogs = new ArrayList<Dog>();
dogs.add(new Dog()); dogs.add(new Dog());

animals = dogs;

One important difference is that, it is not possible to add elements to the animals list, though the only exception is adding null elements. This is called the Upper Bound for the animals list.
Because extends also tell us that only subtype of Animal (extended from Animal) are allowed. I can't see the difference and necessity of lower bounds. What is going on here?