Home > Net >  Override a method in Java by providing a Subtype as a Parameter
Override a method in Java by providing a Subtype as a Parameter

Time:06-23

I want to override a method in Java by passing a concrete subtype of the parameter type that is specified in the super class. See the following example. Is there a way to get this working in Java?

    interface A {
        <T> T f(V<T> v);
    }

    interface V<T> {
        T v();
    }

    class B implements A {

        @Override // Here it gives error: Method does not override method from its superclass
        public <T> T f(V1<T> v) {
            return v.v1();
        }
    }

    interface V1<T> extends V<T> { 
        T v1();
    }

I have also tried this version for A but doesn't work:

interface A {
   <T, U extends V<T>> T f(U v);
}

CodePudding user response:

You can get close to what you want by taking multiple generic arguments at the interface level and none at the function level.

interface A<T, S extends V<T>> {
    public T f(S v);
}

class B<T> extends A<T, V1<T>> {

    @Override // Here it gives error: Method does not override method from its superclass
    public T f(V1<T> v) {
        return v.v1();
    }
}

Note that this isn't quite the guarantee you were looking for, as someone could come along and write some class C extends A<Integer, V1<Integer>> that only works for integers and no other type. But to do that, you'd need something called higher-kinded polymorphism which is not supported in Java.

CodePudding user response:

The definition of the method f in the subclass violates the Liskov substitution principle, which says that should be able to use a child instance whenever the parent is expected.

public <T> T f(V1<T> v)

Method f in the parent class expects V<T> as an argument. And V is a super type of V1 which means that the method declared by the child expects a more narrow type. I.e. the instance of a child is not able to handle all subtypes of V and hence can't substitute its parent.

And from the practical point of view, it's clearly not a valid method overriding (at least in Java). Method signatures should match exactly, otherwise it's a method overloading, which is the case here.

And you're getting a compilation error because you've applied @Override annotation and the compiler fails to find a method with matching signature in the parent class, and also because the contract defined by the interface A hasn't been't implemented.

The only exception related to the overriding of generic methods that we have is the possibility to override a method that expects a generic parameter like Collection<T> to be overridden by a non generified method that expects a Collection of row type (it was done in order to facilitate transition to generics when they were introduced in the language).

  • Related