我正在尝试定义一个实现Comparable的抽象类。当我使用以下定义定义类时:
public abstract class MyClass implements Comparable <MyClass>
子类必须实现compareTo(MyClass object)
。相反,我希望每个子类都实现compareTo(SubClass object)
,接受自己类型的对象。当我尝试用以下内容定义抽象类时:
public abstract class MyClass implements Comparable <? extends MyClass>
它抱怨“超类型可能没有指定任何通配符。”
有解决方案吗?
答案 0 :(得分:43)
在我看来,这有点过于冗长,但有效:
public abstract class MyClass<T extends MyClass<T>> implements Comparable<T> {
}
public class SubClass extends MyClass<SubClass> {
@Override
public int compareTo(SubClass o) {
// TODO Auto-generated method stub
return 0;
}
}
答案 1 :(得分:18)
除了您在宣布签名时遇到的机械困难之外,目标没有多大意义。您正在尝试建立一个协变比较函数,它打破了建立派生类可以定制的接口的整个想法。
如果您定义某个子类SubClass
,使其实例只能与其他SubClass
实例进行比较,那么SubClass
如何满足MyClass
定义的契约?回想一下MyClass
说它和从它派生的任何类型都可以与其他MyClass
实例进行比较。您试图使SubClass
不成立,这意味着SubClass
不符合MyClass
的合同:您不能将SubClass
替换为MyClass
,因为SubClass
的要求更严格。
这个问题集中在协方差和逆变,以及它们如何允许函数签名通过类型派生来改变。您可以放松对参数类型的要求 - 接受比超类型的签名要求更广泛的类型 - 并且您可以加强对返回类型的要求 - 承诺返回更窄的类型超出超类型的签名。这些自由中的每一个仍然允许完全替换派生类型的超类型;通过超类型接口使用派生类型时,调用者无法区分,但使用派生类型的调用者可以利用这些自由。
Willi's answer教授一些关于泛型声明的内容,但我建议你在以语义为代价接受该技术之前重新考虑你的目标。
答案 2 :(得分:3)
参见Java自己的例子:
public abstract class Enum<E extends Enum<E>> implements Comparable<E>
public final int compareTo(E o)
关于seh的评论:通常论证是正确的。但泛型使类型关系更复杂。在Willi的解决方案中,SubClass可能不是MyClass的子类型....
SubClassA
是MyClass<SubClassA>
的子类型,但不是MyClass<SubClassB>
的子类型
类型MyClass<X>
定义了compareTo(X)
的合同,其所有子类型都必须遵守该合同。那里没有问题。
答案 3 :(得分:1)
我不确定你需要捕获:
首先,将compareTo添加到抽象类...
public abstract class MyClass implements Comparable <MyClass> {
@Override
public int compareTo(MyClass c) {
...
}
}
然后添加实现......
public class MyClass1 extends MyClass {
...
}
public class MyClass2 extends MyClass {
...
}
调用compare将调用超类型方法...
MyClass1 c1 = new MyClass1();
MyClass2 c2 = new MyClass2();
c1.compareTo(c2);
答案 4 :(得分:1)
public abstract class MyClass<T> implements Comparable<T> {
}
public class SubClass extends MyClass<SubClass> {
@Override
public int compareTo(SubClass o) {
// TODO Auto-generated method stub
return 0;
}
}
答案 5 :(得分:1)
找到另一种解决方案:
解决方案应如下所示:
public abstract class MyClass implements ComparableFoo,Comparable<ComparableFoo> {
public int compareTo(ComparableFoo o) {
// your implementation
}
}
这个解决方案意味着更多的东西可能会实现ComparableFoo - 这可能不是这种情况,但随后您将编码到接口并且泛型表达式很简单。
答案 6 :(得分:0)
我知道你说你想要&#34; compareTo(SubClass对象),接受它自己类型的对象&#34;,但我仍然建议像这样声明抽象类:
public abstract class MyClass implements Comparable <Object>
并在覆盖MySubClass中的compareTo时执行instanceof检查:
@Override
public int compareTo(Object o) {
if (o instanceof MySubClass)) {
...
}
else throw new IllegalArgumentException(...)
}
类似于&#39;等于&#39;或克隆&#39;