I got this one from a google I/O puzzler talk given by Joshua Bloch. Here's the code
public class Glommer<T> {
String glom(Collection<?> obj){
String result = "";
for(Object o : obj){
result += o;
}
return result;
}
int glom(List<Integer> ints){
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 Glommer().glom(strings));
}
this main method throws an exception because new Glommer
is a raw type and hence all the generics in Glommer
is erased, so it ends up calling int glom(List<Integer> ints)
rather than String glom(Collection<?> obj)
.
My question is, even if I called glom()
as new Glommer<Integer>().glom(strings)
shouldn't it call the int glom(List<Integer> ints)
method since due to type erasure, this method is effectively int glom(List ints)
and strings
is of type List
not Collection
?
- Erasure is a type of alteration in document. It can be classified as chemical erasure and physical erasure.
Whenever you want to restrict the type parameter to subtypes of a particular class you can use the bounded type parameter. If you just specify a type (class) as bounded parameter, only sub types of that particular class are accepted by the current generic class. These are known as bounded-types in generics in Java.
What Is Type Erasure? Type erasure can be explained as the process of enforcing type constraints only at compile time and discarding the element type information at runtime. Therefore the compiler ensures type safety of our code and prevents runtime errors.
Cannot Use Casts or instanceof With Parameterized Types. Cannot Create Arrays of Parameterized Types. Cannot Create, Catch, or Throw Objects of Parameterized Types. Cannot Overload a Method Where the Formal Parameter Types of Each Overload Erase to the Same Raw Type.
The called method is defined at compilation time, not at runtime.
If you add a parameter to your constructor call, the compiler will have enough information to know that it has to call the first method. Otherwise, it's just as if generics didn't exist. In both case, the called method will always stay the same at runtime.
EDIT Some people seem to doubt, so here's another example:
public class Test {
private static void test(Object object) {
System.out.println("Object method");
}
private static void test(Integer integer) {
System.out.println("Integer method");
}
public static void main(String[] args) {
Object object = Integer.valueOf(0);
test(object);
}
}
The result is:
Object method
You pass an Integer to your method, but all that the compiler knows at compile time is that it's an object. The jvm doesn't automagically change the method call even though the Object is actually an Integer.
You can read more about Raw Types to understand it fully
Basically, raw types are for using legacy code, almost anything in a raw class will become raw itself, in this case those 2 methods.
So when it is raw there is a method that gets a List
and one for Collection
so its called the List
one, if its not raw, the methods are not raw also and it will call the Collection
one because it has the extra information
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