|
Generics for robustness ? Think again this example...Does it work?
Declaring an array with typed generics is illegal. E.g.
List<String> [] a = new ArrayList<String> [3];// is illegal
Why it is so? I have a reason: Assume that they are legal, what will be the complications? Consider the following.
---------------------------------1----------------------------------------------------------------------------------------
List<String> [] listArray = new ArrayList<String>[10]; // assume it is legal
Object[] oa = listArray;
oa[0] = new ArrayList<Integer>();
….
String a = listarray[0].get(0);//produces ClassCastException
--------------------------------2----------------------------------------------------------------------------------------
List<?>[] listArray = new ArrayList<?>[10];
Object[] oa = listarray;
oa[0] = new ArrayList<Integer>();
Integer a = (Integer) listArray[0].get(0);//explicit cast is required or else compile error
Having array declared as “new ArrayList<String>[10]” is not safe compared to “new ArrayList<?>[10]”. The reason is because the compiler can detect type error in the latter case than the former. The former results in runtime ClassCastException Exception. Generic is design mainly to prevent such type error.
Having understood the previous case, consider the following requirement in using generics.
“primitive types and array types cannot be used as type bounds. However array types can be used as wildcard bounds. “
For example:
void method1(A<T extends ArrayList<String>[]> a){} is illegal
void method2(A<? extends ArrayList<String>[]> b){} is legal
I don’t understand why using array types as wildcard bounds are OK but NOT for type bounds. I made an experiment and made a conclusion that array types cannot be used as both type bounds and wildcard bounds. Something is strange. Why did the SUN specification group allow it? I will reason by using the following example.
------------------------------------------
import java.util.*;
public class A<T>{
T[] y;
public void method(A<? extends AbstractList<String>[]> x){
/* No compilation error: reference variable y recognize itself as an array as it is declared as such and can take in multidimensional array because of "? extends AbstractList<String>[]" type */
x.y[0][0] = new ArrayList<String>();* //Line 1 *
Object[][] d = x.y;
ArrayList<Integer> g = new ArrayList<Integer>(); //an ArrayList of Int
g.add(4);
d[0][0] = g; //ok, no compilation error/warning
String f = x.y[0][0].get(0);// ok, no compilation error/warning
System.out.println(f);
}
public void add(T s){
/* Unchecked cast warning: the reason i think; for casting the left-hand and the right-hand sides must have subtype and supertype relationship. Here it is not certain, that's why the error. */
y = (T[])s; *// Line 2 *
}
public static void main(String[] argv){
A<ArrayList<String>[]> p = new A<ArrayList<String>[]>();
ArrayList<String>[] g = new ArrayList[2]; //Line 3: compilation warning
g[0] = new ArrayList<String>();
g[0].add("George");
g[1] = new ArrayList<String>();
g[1].add("Bush");
p.add(g);
A<ArrayList<String>[]> f = new A<ArrayList<String>[]>();
f.method(p);
}
}
-----------------------------------------------------------------
Except for 2 compilation warnings at line 2 and 3, there are no other errors/warnings. But at runtime the following exception is produced.
Exception in thread "main" java.lang.ClassCastException: [Ljava.util.ArrayList;
cannot be cast to [[Ljava.util.AbstractList;
Why it is so? Using generics should not produce ClassCastException. For this reason I feel array types cannot be used as type bounds and wildcard bounds.
Anyone willing to give your clarifications?
Thank you.
|