什么是“覆盖等效”,它与@Override有何关系?

阅读Javadoc的注释,我遇到了以下规则:@Override

如果某个方法使用此批注类型进行批注,则编译器需要生成错误消息,除非至少满足以下条件之一:

  • 该方法会重写或实现在超类型中声明的方法。
  • 该方法具有一个签名,该签名与 Object 中声明的任何公共方法的签名等效。

我对第一点很清楚,但我不确定第二点。

“覆盖等效”是什么意思?在这方面,公共方法有何特殊之处?为什么这不包括在第一个标准之下?Object

此外,这只适用于 Java 7+ 文档。Java 6 文档没有说明任何关于覆盖等效性的内容。为什么要进行更改?


更新:

在进一步咨询 JLS(第 8.4.2 节)后,我发现了以下对覆盖等效性的解释:

方法的签名是方法签名的子签名,如果出现以下任一情况:m1m2

  • m2具有 与 相同的签名,或者m1
  • 的签名与 的签名的擦除 (§4.6) 相同。m1m2

两个方法签名 m1m2覆盖等效签名,其中 m1m2 的子签名,或者 m2m1 的子签名。

据我所知,这回答了第一个问题(“这是什么意思?”)和第三个问题(“为什么第一个条件不涵盖这一点?”)。

如果我理解正确(如果我没有理解,请通知我!),只有一种情况,其中两种方法是覆盖等效的,并且不属于原始问题的第一个条件。当子类方法的签名的擦除与超类方法的签名相同,但相反时,就是这种情况。

因此,只有当我们在尝试“重写”类的公共方法时尝试添加类型参数时,原始问题的第二个条件才会发挥作用。我尝试了以下简单示例来测试这一点,使用未使用的类型参数:Object

public class Foo {
    @Override
    public <T> boolean equals(Object obj) {
        return true;
    }
}

当然,此类不会编译,因为该方法实际上不会重写该方法,因此会与该方法发生冲突。但是,由于使用注释,我仍然收到编译器错误。我假设此示例满足第二个使用条件是错误的吗?或者编译器是否生成此错误,尽管不需要这样做?equals@Override@Override


答案 1

这样做的原因是允许您在接口中使用注释,这些接口不从接口继承,而是隐式声明所有公共方法(请参阅 JLS 第 9.2 节接口成员)。因此,您可以声明如下接口:@OverrideObjectObject

interface Bar { @Override int hashCode(); }

但是,不允许声明以下接口:

interface Quux { @Override Object clone(); }

因为该方法不是在接口中隐式声明的(它不是)。clone()public

这在 JLS 第 9.6.3.4 节中进行了描述@Override(Javadoc 的仍然引用旧的节号)@Override


答案 2

您的问题基本上是一个设计问题,JLS解释了它:

“子签名的概念旨在表达两个签名不相同的方法之间的关系,但其中一个可以覆盖另一个。具体而言,它允许其签名不使用泛型类型的方法重写该方法的任何生成版本。这很重要,这样库设计人员就可以独立于定义库的子类或子接口的客户端自由地生成方法。

您的代码不是此的有效示例,请参阅下面的代码,它的工作原理:

public class SubSignatureTest extends SignatureTest {

    @Override
    public List test(Collection p) {
        return null;
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub

    }

}

class SignatureTest {

    public <T> List<T> test(Collection<T> t) {
        return null;

    }
}

重点是超类和子类的签名在擦除后应该是相同的。

编辑:当我们谈论覆盖等价性时,父类应该有泛型方法,子类应该有非泛型方法。下面是一个示例来解释这一点。下面的代码将不起作用,因为子类具有泛型方法。让我们假设java允许,那么main方法中的调用将始终失败:

class A{
       public int compareTo(Object o){
               return 0;
       }
}

class B extends A implements Comparable<B>{
       public int compareTo(B b){
               return 0;
       }

       public static void main(String[] argv){
               System.out.println(new B().compareTo(new Object()));
       }
}

在类B中,编译后的方法将如下所示:

public int compareTo(Object x){
    return compareTo((B)x);
  }

这意味着这始终是错误的:.因此,如果父类具有非泛型方法,java 将不允许子类具有泛型方法。因此,您无法为对象类定义重写等价方法。new B().compareTo(new Object())

希望澄清。

我使用帖子 http://lists.seas.upenn.edu/pipermail/types-list/2006/001091.html 作为参考,它有很多细节。


推荐