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

用泛型实现接口的Java抽象类,java,generics,abstract-class,Java,Generics,Abstract Class,我试图定义一个实现可比较的抽象类。当我用以下定义定义类时: public abstract class MyClass implements Comparable <MyClass> 它抱怨“超类型不能指定任何通配符。” 有解决方案吗?在我看来,这有点过于冗长,但有效: public abstract class MyClass<T extends MyClass<T>> implements Comparable<T> { } public

我试图定义一个实现可比较的抽象类。当我用以下定义定义类时:

public abstract class MyClass implements Comparable <MyClass>
它抱怨“超类型不能指定任何通配符。”


有解决方案吗?

在我看来,这有点过于冗长,但有效:

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

}

公共抽象类MyClass实现了可比较的{
}
公共类子类扩展了MyClass{
@凌驾
公共整数比较(o子类){
//TODO自动生成的方法存根
返回0;
}
}

我不确定您是否需要捕获:

首先,将compareTo添加到抽象类

public abstract class MyClass implements Comparable <MyClass> {

@Override
public int compareTo(MyClass c) {
...
}    
}
调用compare将调用超级类型方法

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

c1.compareTo(c2);

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

如果您定义某个子类
子类
,使其实例只能与其他
子类
实例进行比较,那么
子类
如何满足
MyClass
定义的契约?回想一下,
MyClass
表示它和从它派生的任何类型都可以与其他
MyClass
实例进行比较。您试图使
子类
不符合这一点,这意味着
子类
不满足
MyClass
的合同:您不能用
子类
代替
MyClass
,因为
子类
的要求更严格

这个问题集中在协方差和逆变换上,以及它们如何允许函数签名通过类型派生进行更改。您可以放宽对参数类型的要求,该参数类型接受比超类型签名要求更宽的类型,并且可以加强对返回类型的要求,该返回类型承诺返回比超类型签名更窄的类型。这些自由度中的每一个仍然允许派生类型完美地替代超类型;调用程序在通过超类型的接口使用派生类型时无法区分两者之间的区别,但具体使用派生类型的调用程序可以利用这些自由度


教您一些关于泛型声明的知识,但我敦促您在接受该技术之前重新考虑您的目标,以牺牲语义为代价。

参见Java自己的示例:

public abstract class Enum<E extends Enum<E>> implements Comparable<E>
    public final int compareTo(E o)
公共抽象类Enum实现了可比较的
公共最终国际比较(E/o)
关于seh的评论:通常这个论点是正确的。但是泛型使类型关系更加复杂。在Willi的解决方案中,子类可能不是MyClass的子类型

subpassa
MyClass
的子类型,但不是
MyClass


type
MyClass
compareTo(X)
定义一个契约,它的所有子类型都必须遵守该契约。这里没有问题。

公共抽象类MyClass实现了可比性{
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;
    }

}
} 公共类子类扩展了MyClass{ @凌驾 公共整数比较(o子类){ //TODO自动生成的方法存根 返回0; } }
我知道您说过希望“compareTo(子类对象),接受自己类型的对象”,但我仍然建议如下声明抽象类:

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

与“等于”或“克隆”类似,找到了另一种解决方案:

  • 在构成comaprable的字段上定义一个接口(例如ComparableFoo)
  • 在父类上实现接口
  • 在父类上实现Comparable
  • 编写您的实现
  • 解决方案应如下所示:

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

    公共抽象类MyClass实现了ComparableFoo,Comparable{
    公共国际比较组织(可比组织){
    //您的实现
    }
    }
    

    这个解决方案意味着可能会有更多的东西实现ComparableFoo——情况可能不是这样,但是您正在对一个接口进行编码,泛型表达式很简单。

    这不正是Cem描述问题的方式吗?如何在<代码> MyCase1或<代码> MyCase2</C> >中使用不同的参数类型实现<代码> > >代码?考虑(1)MyMyL1类扩展MyC类{…};(2)类MyImpl2将MyClass{public int compareTo(MyImpl1 o){…}扩展。MyImpl2做得不对。如果我们假设每个子类都以自己的类作为泛型参数扩展MyClass,那么解决方案是正确的。然而,正如埃默里指出的那样,似乎没有办法确保这一点。@埃默里直接实现
    Comparable
    ,也是如此。没有人会阻止您执行
    MyImpl2实现可比较的
    。但是声明需求会迫使子类实现可比较,而不是假设它。
    公共抽象类MyClass实现可比较的
    ,我同意这个答案。此外,我们应该为接口而不是类编码。实际的实现类可能是匿名类、本地类(嵌套在方法中)、私有类(嵌套在类中)或包私有类,因此不在我们的范围内。我应该可以用
    List
    来存储它们,而不是
    Listseh,谢谢你的回答。实际上,我正在寻找一种契约,它将强制每个子类仅为其自己的类使用compareTo()方法,而不为任何其他子类使用。我编造的泛型定义在这个意义上可能有误导性。我理解,Cem,尽管强制子类定义
    compareTo()
    仍然很奇怪。使用
    Enum
    ,它为派生类型(编译器将为您生成的类型)提供了该定义,这是一种不同寻常的情况。在您的例子中,您只提供了派生类型的义务。是
    public abstract class MyClass implements ComparableFoo,Comparable<ComparableFoo> {
        public int compareTo(ComparableFoo o) {
        // your implementation
        }
    }