Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How Generics at Class Level Parameter works [duplicate]

Tags:

java

generics

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 ?

like image 956
Punit Patel Avatar asked Dec 21 '22 02:12

Punit Patel


2 Answers

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<?> )

like image 144
Alexander Pogrebnyak Avatar answered Dec 22 '22 15:12

Alexander Pogrebnyak


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.

like image 28
GriffeyDog Avatar answered Dec 22 '22 16:12

GriffeyDog