Search code examples
javagenericsinheritancepolymorphismsuperclass

Unable to overwrite method in the subclass because of the undesirably matched type


I have 3 classes. I want to have output "want MyClass" for both myObjStr and myObjInt.

Therefore, I only want the method of the subclass, and I would like to replace the superclass method completely.

But currently, I only got "want MyClass" for myObjStr.

For myObjInt, I mistakenly got "hate MySuperClass" as output (since K unluckily matched int in that case).

Is it possible to do the fix if I am not allowed to modify MyMethod of MySuperClass? MySuperClass is from a standard library so I shouldn't modify it.

Main.java

public class Main {

    public static void main(String[] args) {

        MyClass<String, String> myObjStr = new MyClass<String, String>();
        myObjStr.myMethod("a");
    
        MyClass<Integer, String> myObjInt = new MyClass<Integer, String>();
        myObjInt.myMethod(1);
    
    
    }

}

MySuperClass.java

public class MySuperClass {

    public boolean myMethod(int index) {
        System.out.print("hate MySuperClass, ");
        return false;
    }

}

MyClass.java

public class MyClass<K,V> extends MySuperClass {

    public boolean myMethod(K key) {
        System.out.print("want MyClass, ");
        return false;
    }
}

Solution

  • Super class should also be parametrized with generics:

    public class MySuperClass<K> {
    
        public boolean MyMethod(K index) {
            System.out.print("hate MySuperClass, ");
            return false;
        }
    
    }
    

    And subclass should extend the super class with the same generic:

    public class MyClass<K,V> extends MySuperClass<K> {
    
        @Override
        public boolean MyMethod(K key) {
            System.out.print("want MyClass, ");
            return false;
        }
    }
    

    The compiler sees you are calling a method called MyMethod passing a parameter of type int and expecting a boolean in return.

    If the signature of the superclass was not exactly boolean MyMethod(int) (for example if you rename it MyMethod2), then the compiler wouldn't get confused and would go to the implementation of the subclass as you are expecting.

    However, in this case the signatures are ambiguous and the compiler takes the superclass instead of the subclass for a "better" match of signature.

    NIT: the methods names should start with small letter, hence myMethod instead of MyMethod, following the Java standard conventions.


    If you cannot modify MySuperClass to be parameterized, then you will have to explicitly override the super method in your derived class:

    public class MyClass<K,V> extends MySuperClass {
    
        public boolean MyMethod(K key) {
            System.out.print("want MyClass, ");
            return false;
        }
    
        @Override
        public boolean MyMethod(int index) {
            //Your derived class logic here.
        }
    }