2
class Test {
    public static <T> boolean test(T a, T b) {
        return a.equals(b);
    }

    public static void main(String[] args) {
        int i = 0;
        long j = 0;
        if (!test(i, j)) {
            throw new RuntimeException("i is not equal to j");
        }
    }
}

In the code snippet above I am expecting one of the following two things to happen:

  1. There will be a compiler error, because i is autoboxed to Integer and j is autoboxed to Long and the declaration of the method test requires that both of its arguments are of the same type.

  2. Both i and j to be autoboxed to Long and the code to compile and run showing that i and j are equal.

But what happens actually is i is autoboxed to Integer and j is autoboxed to Long and the code compiles without error. Doesn't this contradict with the declaration of test? What is the reason to allow such code?

qweqq
  • 31
  • 2
  • I assumed that the compiler will "see" that it should find a common class to cast both i and j to and the answer would be Long because that way there is no losing of precision. But as it was explained the compiler sees that it wants i to be autoboxed to Integer and j to be autoboxed to Long and _then_ tries to satisfy T and succeeds by choosing for example Number. (edited as I further understood what actually happened) – qweqq Sep 03 '20 at 14:42

1 Answers1

3

If i is boxed to an Integer and j is boxed to a Long, it's still legal to call the method test with its generic type assumed to be java.lang.Number, which is a supertype of both Integer and Long.

In fact, you can call your test method with any two objects, because T can be taken as the base type Object. The generics on the method do not restrict its arguments at all.

khelwood
  • 55,782
  • 14
  • 81
  • 108