Consider Following code from Java Puzzlers
class Gloam<T>{
String glom(Collection<?> objs ) {
System.out.println("collection");
String result = "";
for (Object o : objs ){
result += o;
}
return result;
}
int glom(List <Integer> ints ) {
System.out.println("List");
int result = 0;
for ( int i : ints )
result += i ;
return result;
}
public static void main(String[] args) {
List<String> strings = Arrays.asList("1", "2", "3");
System.out.println(new Gloam().glom(strings));
}
}
When I run this program it gives class cast exception, But if I provide any Generic argument for Gloam class in main method it works fine.
public static void main(String[] args) {
List<String> strings = Arrays.asList("1", "2", "3");
System.out.println(new Gloam<Date>().glom(strings));
}
I don't understand how generic works in class type parameter ?
With no generic type passed into constructor, all types are erased and the compiler is presented with this choices
String glom ( Collection );
int glom ( List );
The type is also erased from strings
variable defined in main
, so its type is List
.
Because List
is more specific than Collection
it chooses int glom ( List )
.
Now, if you have specified the generic parameter, then no type erasure happens, and compiler knows that it cannot match int glom ( List<Integer> )
to List<String>
, so it falls back to String glom ( Collection<?> )
Once you fail to provide the generic type parameter, all generic typing for the whole class is gone in the eyes of the compiler. The class essentially becomes:
class Gloam<T> {
String glom(Collection objs) {
System.out.println("collection");
String result = "";
for (Object o : objs) {
result += o;
}
return result;
}
int glom(List ints) {
System.out.println("List");
int result = 0;
for (int i : ints)
result += i;
return result;
}
public static void main(String[] args) {
List strings = Arrays.asList("1", "2", "3");
System.out.println(new Gloam().glom(strings));
}
}
So now the compiler will choose the int glom(List ints)
override since that's the most-specific override that matches the call. But it will also result in the class cast exception. When you supply the generic parameter, generics are retained and the String glom(Collection<?> objs )
override matches the call (which is passing a List<String>
), whereas int glom(List <Integer> ints )
does not match because String
is not Integer
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With