I wonder why this is a valid override:
public abstract class A {
public abstract <X> Supplier<X> getSupplier();
public static class B extends A {
@Override
public Supplier<String> getSupplier() {
return String::new;
}
}
}
Whereas this is not:
public abstract class A {
public abstract <X> Supplier<X> getSuppliers(Collection<String> strings);
public static class B extends A {
@Override
public Supplier<String> getSuppliers(Collection<String> strings) {
return String::new;
}
}
}
According to JLS §8.4.8.1, B.getSupplier
must be a subsignature A.getSupplier
:
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.
- ...
Subsignatures are defined in JLS §8.4.2:
Two methods or constructors, M and N, have the same signature if they have the same name, the same type parameters (if any) (§8.4.4), and, after adapting the formal parameter types of N to the the type parameters of M, the same formal parameter types.
The signature of a method m1 is a subsignature of the signature of a method m2 if either:
- m2 has the same signature as m1, or
- the signature of m1 is the same as the erasure (§4.6) of the signature of m2.
So it seems like B.getSupplier
is a subsignature of A.getSupplier
but B.getSuppliers
is not a subsignature of A.getSuppliers
.
I wonder how it can be the case.
If B.getSupplier
is a subsignature of A.getSupplier
because it has the same erasure, then B.getSuppliers
must also have the same erasure as A.getSuppliers
. This should suffice for overriding getSuppliers
to be legal - but it does not.
If B.getSupplier
is a subsignature of A.getSupplier
because it has the same signature, then I wonder what "the same type parameters (if any)" exactly means.
If type parameters are considered, then they should have different type parameters: A.getSupplier
has type parameter X
, B.getSupplier
has none.
If type parameters are not considered then how's getSuppliers
different?
This is more of an academic question about overrides and generics so please don't suggest refactoring code (like moving type parameter X
to the class etc.).
I am looking for a formal, JLS-based answer.
From my point of view B.getSupplier
should not be able override A.getSupplier
as they don't have the same type parameters. This makes the following code (which produces ClassCastException
) legal:
A b = new B();
URL url = b.<URL>getSupplier().get();