Search code examples
javagenericsgeneric-method

Generic method inheritance


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!


Solution

  • 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.