用泛型实现接口的 Java 抽象类

我正在尝试定义一个实现 Compaable 的抽象类:

public abstract class MyClass implements Comparable <MyClass>

子类必须实现 compareTo(MyClass object)。相反,我希望每个子类都实现 compareTo(SubClass object),接受一个自己类型的对象。当我尝试定义抽象类时,比如:

public abstract class MyClass implements Comparable <? extends MyClass>

它抱怨“超类型可能不指定任何通配符。”

有解决办法吗?

32863 次浏览

在我看来,这有点太冗长了,但是很有效:

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;
}


}

我不确定你是否需要捕捉:

首先,将 compareTo 添加到抽象类..。

public abstract class MyClass implements Comparable <MyClass> {


@Override
public int compareTo(MyClass c) {
...
}
}

然后加上实现..。

public class MyClass1 extends MyClass {
...
}


public class MyClass2 extends MyClass {
...
}

调用比较将调用超类型方法..。

MyClass1 c1 = new MyClass1();
MyClass2 c2 = new MyClass2();


c1.compareTo(c2);

除了声明签名时遇到的机械困难之外,这个目标没有多大意义。您试图建立一个协变比较函数,这打破了建立派生类可以定制的接口的整个思想。

如果您定义了一些子类 SubClass,使其实例只能与其他 SubClass实例进行比较,那么 SubClass如何满足由 MyClass定义的约定?回想一下,MyClass是说它和从它派生的任何类型都可以与其他 MyClass实例进行比较。您试图使这种情况不适用于 SubClass,这意味着 SubClass不符合 MyClass的合同: 您不能用 SubClass代替 MyClass,因为 SubClass的要求更严格。

这个问题集中在反变,以及它们如何允许函数签名通过类型派生来改变。您可以对参数的类型提出 放松要求ーー接受比超类型的签名要求更宽的类型ーー也可以对返回类型提出 加强要求ーー承诺返回比超类型的签名更窄的类型。这些自由度中的每一个仍然允许派生类型对超类型的完美替换; 当调用者通过超类型的接口使用派生类型时,他们不能分辨出差异,但是使用派生类型的调用者可以具体地利用这些自由度。

Willi 的回答 教会了我们一些关于通用声明的知识,但是我强烈建议您在接受这项技术之前重新考虑一下您的目标,以牺牲语义为代价。

看看 Java 自己的例子:

public abstract class Enum<E extends Enum<E>> implements Comparable<E>
public final int compareTo(E o)

关于 seh 的评论: 通常论点是正确的。但是泛型使类型关系更加复杂。在 Willi 的解决方案中,子类可能不是 MyClass 的子类型... ..。

SubClassAMyClass<SubClassA>的一个子类型,但不是 MyClass<SubClassB>的一个子类型

类型 MyClass<X>compareTo(X)定义了一个契约,它的所有子类型都必须遵守这个契约。

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;
}


}

我知道您希望“ compareTo (SubClass object) ,接受自己类型的对象”,但是我仍然建议像这样声明抽象类:

public abstract class MyClass implements Comparable <Object>

并在 MySubClass 中重写 compareTo 时执行 instanceof 检查:

@Override
public int compareTo(Object o) {
if (o instanceof MySubClass)) {
...
}
else throw new IllegalArgumentException(...)
}

类似于“等于”或“克隆”

找到了另一个解决办法:

  1. 在组成可比对象的字段上定义一个接口(例如 ComparableFoo)
  2. 在父类上实现接口
  3. 在父类上实现类比。
  4. 编写您的实现。

解决方案应该是这样的:

public abstract class MyClass implements ComparableFoo,Comparable<ComparableFoo> {
public int compareTo(ComparableFoo o) {
// your implementation
}
}

这个解决方案意味着可以实现更多的东西——这种情况可能不会发生,但是您正在编写一个接口,并且泛型表达式很简单。