20

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

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

  • 该方法确实覆盖或实现了在超类型中声明的方法。
  • 该方法的签名与 Object 中声明的任何公共方法的签名等效。

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

“覆盖等效”是什么意思?公共方法Object在这方面的特殊性如何?为什么这不包括在第一个标准中?

此外,这仅适用于 Java 7+ 文档。Java 6 文档没有说任何关于覆盖等效的内容。为什么改变?


更新:

在进一步查阅 JLS(第 8.4.2 节)后,我发现了以下关于覆盖等效的解释:

m1如果满足以下任一条件,方法的签名是方法签名的子签名m2

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

两个方法签名m1并且m2覆盖等效的当且仅当m1是 的子签名m2m2的子签名m1

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

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

那么,原始问题的第二个条件只会在我们尝试“覆盖”Object类的公共方法时尝试添加类型参数时发挥作用。我尝试了以下简单示例来测试它,使用未使用的类型参数:

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

当然,这个类不会编译,因为该方法实际上并没有覆盖该equals方法,因此会与它发生冲突。但我仍然收到使用@Override注释的编译器错误。假设这个例子符合第二个使用条件,我错了@Override吗?或者编译器是否会产生此错误,尽管不需要这样做

4

2 回答 2

8

The reason for this is to allow you to use the @Override annotation in interfaces, which do not inherit from Object but implicitly declare all public methods from Object (see JLS section 9.2 interface members). You are thus allowed to declare an interface like:

interface Bar { @Override int hashCode(); }

However, you would not be allowed to declare the following interface:

interface Quux { @Override Object clone(); }

since the clone() method is not implicitly declared in an interface (it is not public).

This is described in JLS section 9.6.3.4 @Override (the Javadoc for @Override still refers to an old section number)

于 2013-05-03T21:38:25.913 回答
4

您的问题基本上是一个设计问题,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);
  }

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

希望澄清。

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

于 2013-04-28T06:43:33.110 回答