为什么我不能为一个继承另一个的 类 实现 Comparable?

Why I can't implement Comparable for both the classes where one inherits other?

假设我有两个 类 人和雇员。人正在实施 Comparable。当我也尝试为 Employee 实现 Comparable 时,我遇到了编译器错误。我的代码是:

class Person implements Comparable<Person>{
            protected int age;
            public Person(int age) {
                this.age = age;
            }
            @Override
            public int compareTo(Person o) {
                //if( o instanceof Employee) return 0;
                return age - o.age;
            }
            
            public String toString() {
                return ""+age;
            }
}
        
class Employee extends Person implements Comparable<Employee>{
            public Employee(int age) {
                super(age);
            }
            
            public String toString() {
                return ""+age;
            }
}

错误是:

The interface Comparable cannot be implemented more than once with different arguments: Comparable<Hierarchy.Person> and Comparable<Hierarchy.Employee>

我明白这是 Type Erasures 的原因。因此,将为 类 添加一个 Bridge 方法,它将 Object o 作为参数。这是不允许的。我的理解对吗?

我的愚蠢问题是:为什么不能像函数重写那样处理它?

关于覆盖和过载的简短回答

您的理解是全球正确的。您不能同时实施 Comparable<Person>Comparable<Employee>。由于类型擦除,这基本上会导致两个方法 int compareTo(Object) 具有相同的名称和签名,这是不允许的。

但是,对于您的第二个方法 int compareTo(Employee),它并不是一个覆盖恰恰是因为一个对象,顺便说一下,一个人,并不总是一个雇员。需要显式强制转换。因此,这两个方法没有相同的签名,因此第二个方法不是第一个方法的重写。

如果您删除 @Override 注释,没关系。您的方法不是 override,但它是完全有效的 overload.

提醒一下,

  • 覆盖 正在用子class 中的另一个替换一个方法。覆盖方法必须具有相同名称和签名(return类型协方差除外)。
  • 重载 是在同一个 class 中使用多个同名 的方法。这些方法必须具有不同的签名

关于为什么不允许的详细回答

暂时假设允许实施 Comparable<Person>Comparable<Employee>

编译器在 class Person:

中生成这个桥接方法
public int compareTo (Object o) {
  return compareTo((Person)o);
}

编译 class Employee 时,编译器同样应该生成这个:

public int compareTo (Object o) {
  return compareTo((Employee)o);
}

如上所述,int compareTo(Employee) 不能覆盖 int compareTo(Person)。然而,上面Employee中的第二个桥接方法显然是对Person中第一个的重写。 问题从这里开始。

假设我们有这段代码:

List persons = new ArrayList();
persons.add(new Person(...));
person.add(new Employee(...));
person.add(new Employee(...));
persons.add(new Person(...));
...
Collections.sort(persons);

您将在排序过程中比较 Employee 和 Person,并且将抛出 ClassCastException。 除了能够对不同类型的元素进行排序这一有争议的问题之外,您真的期待它吗?

现在假设编译器不会在 class Employee 中生成覆盖桥接方法,并且要排序的列表只包含 Employee 类型的对象。 您的方法 int compareTo(Employee) 永远不会被调用,因为 Person 中的桥接方法只调用 int compareTo(Person)。不会抛出任何异常,但代码可能不会执行您期望的操作。

那么,编译器应该做什么呢?是否覆盖桥接方法? 也许这两种解决方案中的一种在您的特定情况下是可以接受的,但编译器无法猜测是哪一种(如果有的话)。

再举一个问题比较明显的例子:

interface I1<T> {
  public void m (T t);
}

interface I2<U> {
  public void m (U u);
}

class A implements I1<A> {
  @Override public void m (A a) { ... }
}

class B extends A implements I2<B> {
  @Override public void m (B b) { ... }
}

在这里,编译器必须决定是在其桥接方法中调用 I1 还是 I2 的方法 void B::m(Object)。如果您尝试编译这段代码,您会得到更好的问题线索:

error: name clash: class B has two methods with the same erasure, yet neither overrides the other
@Override public void m (B b) {
^
first method:  m(B) in I2
second method: m(A) in I1