The letter E and T stand for Element and Type respectively, but take note they are not enforced by the compiler or anything like that. You can pretty much put anything there including full words, but it's recommended you use single capital letters so it's better to distinguish them (lowercase words look like variable names, words starting with capital letters look like classes, and full uppercase words look like constants)
As for the use, think of it this way. When you create an array you can create Object[]
, String[]
, Integer[]
, SomeClass[]
, which tells you exactly what is in there. Until generics where introduced the collections/map classes (List, Set, Map) had the problem that you could put anything in there (some may argue that that's not a problem). So now you can create List<String>
, List<Object>
similar to arrays. There are some differences though. For example String[]
extends Object[]
, but List<String>
does NOT extend List<Object>
so you can't put a string list instance in a object list variable.
The advantage of generics is that you can have them on any class, and a class can have more than one generic parameter (like Map<K, V>
). You can think of it as Class
parameters given to instances of other classes, that tell them what types their methods should receive or return.
And yes the point is that the compiler can check if you give them the right kind of parameters, so that you can avoid ClassCastExceptions which would appear at runtime. For example before generics you could do:
String s = "";
List l = new ArrayList();
l.add(s);
Integer i = (Integer)l.get(0); // ClassCastException
but with generics:
String s = "";
List<String> l = new ArrayList<String>();
l.add(s);
Integer i = (Integer)l.get(0); // compiler warning: cannot cast from String to Integer
Also, you can have a generic type parameter on a single method like in your example (the class itself doesn't need to have a type parameter for this). This tells the compiler that that method must match all instances of the type parameter on the method parameters and/or return type. In your example calling it like:
String[] a = new String[1];
List<Integer> l = new ArrayList<Integer>();
fromArrayToCollection(a, l);
will result in a compile error, since the method must receive a T[]
and a Collection<T>
, T here being the same. But you gave it a String[]
(so T here is String) and a List<Integer>
(so T here is Integer, not String). If l was List<String>
though, it would work.
Also notice that List<T>
extends Collection<T>
since List extends Collection, but List<T>
does not extends List<S>
even if T extends S (whatever T and S may be).
Oh, and you can have wildcards on generics specifying limits for the classes that may replace the type paramter:
public <T extends SomeClass> void fromArrayToCollection(T[] a, COllection<T> c);
This way the method will work if you give it SomeClass[] or SomeChildClass[] (where SomeChildClass that extends SomeClass), but not Object[] or String[].