11

I realized today that this compiles and runs fine:

public class Test {
    public static <T> T handle(T val) {
        System.out.println("T");
        return val;
    }

    public static <T extends String> T handle(T val) {
        System.out.println("T extends String");
        return val;
    }
}

The two handle methods has the same name, and same number and type (?) of parameters. The only difference is that the second handle method has a stricter generic bound. IDE does not complain at all, and the code compiles fine. At run time method is selected as expected - e.g. Test.handle("this is a string") will call into the second method and Test.handle(10) will invoke the first one.

Is generics bound considered part of the method signature? or is it a method overload resolution magic?

lealceldeiro
  • 14,342
  • 6
  • 49
  • 80
Xinchao
  • 2,929
  • 1
  • 24
  • 39
  • 6
    In short: `` is erased to `String`, while only `` is erased to `Object` so compiler will create two overloaded methods: `handle(Object)` and `handle(String)` and in other places those methods can be picked according to argument type. – Pshemo Jul 20 '18 at 18:11
  • Official tutorial about this subject: [Erasure of Generic Methods](https://docs.oracle.com/javase/tutorial/java/generics/genMethods.html) – Pshemo Jul 20 '18 at 18:18

2 Answers2

12

Generics offer compile-time type-safety; At runtime, your methods erase to the following:

public static Object handle(Object val) {
    System.out.println("T");
    return val;
}

public static String handle(String val) {
    System.out.println("T extends String");
    return val;
}

Due to method overloading, handle(String) will be called when passing a String, and handle(Object) will be called when passing any other Object (keep in mind String is final and can have no children).

Jacob G.
  • 28,856
  • 5
  • 62
  • 116
2

The bound of the generics is considered.

In the first case, the bound is Object; in the second case, the bound is String.

When types are erased, the bound is used in place of the type variable, so these become simply an overload taking (and returning) Object and String parameters, respectively.

Nothing wrong with that.

Andy Turner
  • 137,514
  • 11
  • 162
  • 243