使用泛型返回类型重写方法失败,添加参数后
我想知道为什么这是一个有效的覆盖:
public abstract class A {
public abstract <X> Supplier<X> getSupplier();
public static class B extends A {
@Override
public Supplier<String> getSupplier() {
return String::new;
}
}
}
而这不是:
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;
}
}
}
根据 JLS §8.4.8.1,必须是子签名:B.getSupplier
A.getSupplier
在类 C 中声明或由类 C 继承的实例方法 mC,从 C 重写在类 A 中声明的另一个方法 mA,如果以下所有条件都为真:
- ...
- mC 的签名是 mA 签名的子签名 (§8.4.2)。
- ...
子签名在 JLS §8.4.2 中定义:
如果两个方法或构造函数(M 和 N)具有相同的名称、相同的类型参数(如果有)(§8.4.4),并且 N 的形式参数类型适应 M 的类型参数后,具有相同的形式参数类型,则它们具有相同的签名。
方法 m1 的签名是方法 m2 签名的子签名,如果出现以下任一情况:
- m2 具有与 m1 相同的签名,或者
- m1 的签名与 m2 签名的擦除 (§4.6) 相同。
因此,它似乎是 的子签名,但不是 的子签名。B.getSupplier
A.getSupplier
B.getSuppliers
A.getSuppliers
我想知道怎么会这样。
如果 是 的子签名,因为它具有相同的擦除,则还必须具有 与 相同的擦除。这应该足以使推翻是合法的 - 但事实并非如此。B.getSupplier
A.getSupplier
B.getSuppliers
A.getSuppliers
getSuppliers
如果 是 一个子签名,因为它具有相同的签名,那么我想知道“相同类型参数(如果有的话)”到底是什么意思。B.getSupplier
A.getSupplier
如果考虑类型参数,那么它们应该具有不同的类型参数:具有类型参数 ,没有。
如果不考虑类型参数,那么有什么不同?A.getSupplier
X
B.getSupplier
getSuppliers
这更像是一个关于重写和泛型的学术问题,所以请不要建议重构代码(比如将类型参数移动到类等)。X
我正在寻找一个正式的,基于JLS的答案。
从我的角度来看,应该不能覆盖,因为它们没有相同的类型参数。这使得以下代码(产生)合法:B.getSupplier
A.getSupplier
ClassCastException
A b = new B();
URL url = b.<URL>getSupplier().get();