Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java generics type erasure of method parameters

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?

like image 490
fo_x86 Avatar asked Dec 20 '12 16:12

fo_x86


People also ask

What are the two 2 types of Erasure?

- Erasure is a type of alteration in document. It can be classified as chemical erasure and physical erasure.

How do you restrict the types used as type arguments in generic classes and methods?

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.

How does type erasure work?

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.

What are not allowed for generics?

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.


2 Answers

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.

like image 99
WilQu Avatar answered Sep 29 '22 05:09

WilQu


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

like image 40
Aviram Segal Avatar answered Sep 29 '22 04:09

Aviram Segal