我很难想到这个标题,所以请原谅我。
我有一个使用以下方法的界面:
public interface Algorithm<E,F> {
public Set<? extends Algorithm<E,F>> map(int numPartitions);
public F reduce(Set<? extends Algorithm<E,F>> partitions);
}
以及使用以下方法实现Algorithm
的类:
public class LinearSearch<T> implements Algorithm<List<T>, Integer> {
@Override
public Set<LinearSearch<T>> map(int numPartitions) {
return null;
}
@Override
public Integer reduce(Set<LinearSearch<T>> partitions) {
return null;
}
}
现在奇怪的是Eclipse正在抱怨第二种方法reduce
。
The method reduce(Set<LinearSearch<T>>) of type LinearSearch<T> must override or implement a supertype method.
尽管map
方法很好,但这是事实。那么我哪里出错?
答案 0 :(得分:10)
覆盖方法和参数类型
在reduce
方法上,参数必须为Set<? extends Algorithm<List<T>,Integer>>
。它必须包含Set<? extends Algorithm<List<T>,Integer>>
,而不仅仅是Set<LinearSearch<T>>
。覆盖方法时,不能缩小参数类型。
JLS, Section 8.4.8.1详述了重写方法的签名:
在类C中声明的实例方法m1将覆盖在类A中声明的另一个实例方法m2,如果以下所有条件都为真:
C是A的子类。
m1的签名是m2签名的子签名(§8.4.2)。
或者:
m2在与C或
相同的包中具有默认访问权限是公共的,受保护的或声明的m1会覆盖方法m3(m3与m1不同,m3与m2不同),这样m3会覆盖m2。
这里,“subsignature”是指在类型擦除后匹配的参数类型。
覆盖方法和返回类型
但为什么map
方法有效呢?因为Java允许开发人员缩小子类的重写方法的返回类型。
另一个section of the JLS, 8.4.5,涵盖了覆盖方法中的返回类型:
如果返回类型是引用类型,则返回类型可能会因覆盖彼此的方法而异。 return-type-substitutability的概念支持协变返回,即返回类型到子类型的特化。
当且仅当满足以下条件时,具有返回类型R1的方法声明d1是具有返回类型R2的另一个方法d2的return-type-substitutable:
如果R1无效,则R2无效。
如果R1是基本类型,则R2与R1相同。
如果R1是参考类型,则:
R1可以是R2的子类型,也可以通过未经检查的转换(第5.1.9节)将R1转换为R2的子类型,或
R1 = | R2 |
(强调我的)
答案 1 :(得分:2)
您的方法标题应如下
public Integer reduce(Set<? extends Algorithm<List<T>, Integer>> partitions)
要覆盖方法,必须使用完全相同的参数类型。如果不是,则不认为是相同的方法。
请注意,类型<E,F>
是该标头的参数化部分,因此Java为您提供了一些自由,并允许您使用类定义中指定的类型。