Java抽象类用泛型实现接口

时间:2010-08-28 23:41:33

标签: java generics abstract-class

我正在尝试定义一个实现Comparable的抽象类。当我使用以下定义定义类时:

public abstract class MyClass implements Comparable <MyClass>

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

public abstract class MyClass implements Comparable <? extends MyClass>

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

有解决方案吗?

7 个答案:

答案 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的子类型....

SubClassAMyClass<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)

找到另一种解决方案:

  1. 在构成comaprable的字段(例如ComparableFoo)
  2. 上定义一个接口
  3. 在父类
  4. 上实现接口
  5. 在父类上实现Comparable。
  6. 编写您的实施。
  7. 解决方案应如下所示:

    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;