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