20

I have classes in advanced programming at my university and I have a little trouble understanding how this code works.

public final class GenericClass<T> {
    private void overloadedMethod(Collection<?> o) {
        System.out.println("Collection<?>");
    }

    private void overloadedMethod(List<Number> o) {
        System.out.println("List<Number>");
    }

    private void overloadedMethod(ArrayList<Integer> o) {
        System.out.println("ArrayList<Integer>");
    }

    public void method(List<T> l) {
        overloadedMethod(l);
    }

    public static void main(String[] args) {
        GenericClass<Integer> test = new GenericClass<Integer>();
        test.method(new ArrayList<Integer>());
    }
}

Why does this code print "Collection<?>"?

Paul Bellora
  • 54,340
  • 18
  • 130
  • 181

3 Answers3

14

The declaration of method(List<T> l) does not specify any bounds on the type T. There is no guarantee that T is Number or a subclass of Number. Therefore, the compiler can only decide that this method calls overloadedMethod(Collection<?> o).

Remember: after compilation, the information about generics is not available anymore in the class files.

rajah9
  • 11,645
  • 5
  • 44
  • 57
gogognome
  • 727
  • 8
  • 24
  • thanks, your answer explains even why after changing `overloadedMethod(List o)` to `overloadedMethod(List> o)` program prints out `List` instead of `Collection>` – Tomasz Bielaszewski Mar 12 '13 at 13:24
  • the most important thing is your last sentence. That explains everything! – Obl Tobl Mar 12 '13 at 13:28
  • Pretty good answer, but -1 to draw your attention to the fact that declaring `GenericClass` instead results in the same call to `overloadedMethod(Collection>)`. So there's something else going on here. – Paul Bellora Mar 12 '13 at 16:49
  • Hint: it would only work if you changed to `overloadedMethod(List extends Number> o)`. – Paul Bellora Mar 12 '13 at 17:03
-1

Whenever you define a generic type, a corresponding raw type is automatically provided This method

public void method(List<T> l) {

}

is replacing with

public void method(List<Object> l) {

}

If You read about Wildcard types, You will see that List<Number> and List<Object> or ArrayList<Integer> and List<Object> hasn't any type relationship. List<Object> is a subtype of the Collecion<?> therefore this method is called.

Arsen Alexanyan
  • 3,061
  • 5
  • 25
  • 45
  • Actually, the reasoning here isn't enough to answer the question. The compiler decides which method overload to call, which happens *before* type erasure. – Paul Bellora Mar 12 '13 at 16:47
-1

when you deal with method overloading you must put three concepts in your mind:

  1. Widening
  2. Boxing
  3. Var_args

your problem lies in the first point which is widening, the java compiler gives priorities to each of these concepts the same order as they are listed above, so it prefers widening and when you call your method as test.method(new ArrayList<Integer>()); the compiler finds that ArrayList<Integer>() could be widened to Collection<?> and since it has the highest priority it calls these version and neglects the other ones Note: if you change the declaration of the other two methods to private void overloadedMethod(ArrayList<?> o) and private void overloadedMethod(List<?> o) the compiler will also call the Collection<?> version because it's the preferred one

Eslam Hamdy
  • 7,126
  • 27
  • 105
  • 165
  • No. if private void overloadedMethod(List> o) { // then List>method will be called over Collection>. – AmitG Mar 12 '13 at 13:25
  • "@Java Player: I keep visiting this forum in office as well and keep update myself as soon as possible. BTW did you try it? If you tried then please drop the conclusion here. – AmitG Mar 12 '13 at 16:23
  • -1 Sorry, but this is wrong. With the specified change it would call `overloadedMethod(List>)` (it wouldn't call `overloadedMethod(ArrayList>)` because `method` takes a `List`. – Paul Bellora Mar 12 '13 at 16:55