1

The question is about the following block of code:

public class SomeClass {
    public static class A {
        public void f(int x) {
            System.out.println("1");
        }

        public void f(Object x) {
            System.out.println("2");
        }
    }

    public static class B extends A {
        public <T> void f(T x) {   // *
            System.out.println("3");
        }
    }
}

Line * does not compile, with the following error:

Description Resource Path Location Type Name clash: The method f(T) of type SomeClass.B has the same erasure as f(Object) of type SomeClass.A but does not override it

To avoid duplicate: I've looked at: Type erasure, overriding and generics , Method has the same erasure as another method in type and while I've received an answer (well partially, because I still didn't completely understand it) why there is a compilation error (to avoid ambiguity because of type erasure? is this it?) the main problem is that I don't understand why, if I switch between the two methods f(Object x) and f(T x) so the code will be like this:

public class SomeClass {
    public static class A {
        public void f(int x) {
            System.out.println("1");
        }


        public <T> void f(T x) {
            System.out.println("3");
        }

    }

    public static class B extends A {
        public void f(Object x) {
            System.out.println("2");
        }
    }
}

I do not receive a compilation error. Why is this happening? What is the key difference for which for the first code I get a compilation error and for the second I don't. Would love some explaining on this, thanks!

fdelafuente
  • 1,114
  • 1
  • 13
  • 24
Mickey
  • 1,405
  • 2
  • 13
  • 33
  • This is essentially by [this answer](https://stackoverflow.com/a/502770/129570): "*For overriding with instance methods you need the overriding method to be a subsignature of the overridden method (JLS 8.4.8.1)*". `void f(Object x)` is a subsignature of ` void f(T x)`, but not vice versa. – Oliver Charlesworth Jul 23 '17 at 16:31
  • Possible duplicate of [Method has the same erasure as another method in type](https://stackoverflow.com/questions/1998544/method-has-the-same-erasure-as-another-method-in-type) – Timothy Truckle Jul 23 '17 at 16:37

2 Answers2

1

One of the answers to one of the questions you linked essentially already addresses this:

For overriding with instance methods you need the overriding method to be a subsignature of the overridden method.

To dig into this a bit more, JLS 8.4.8.1 says this:

An instance method mC declared in or inherited by class C, overrides from C another method mA declared in class A, iff all of the following are true:

  • [...]

  • The signature of mC is a subsignature (§8.4.2) of the signature of mA.

A subsignature is defined in JLS 8.4.2:

The signature of a method m1 is a subsignature of the signature of a method m2 if either:

  • [...]

  • the signature of m1 is the same as the erasure (§4.6) of the signature of m2.

You're considering the following two signatures:

  1. void f(Object x)
  2. <T> void f(T x)

The erasure of #2 is void f(Object x), thus #1 is a subsignature of it. However, vice versa is not true.

Community
  • 1
  • 1
Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
0

The problem here is type erasure as written in the error. This means that your generic type constraint/definition <T> in class B is only regarded by the compiler to do type checking. However, that you put the <T> there is not available in the runtime byte code to do the method resolution.

As such have a look at your public void <T> f(T x) when the type is erased - all that remains is Object (it's just something you can stuff as first parameter). But then this is the same signature as in class A - yielding you the error.

In the second case it's perfectly fine since your class B method will accept any object - so it will of course accept any <T> which you specified in the signature of A.

Michael Rose
  • 7,770
  • 3
  • 22
  • 26