你什么时候使用Java的@Override注释?为什么?

时间:2008-09-18 16:48:27

标签: java annotations

使用Java @Override注释的最佳做法是什么?为什么?

@Override注释标记每个被覆盖的方法似乎有点过分。是否有某些编程情况要求使用@Override和其他永远不会使用@Override的情况?

27 个答案:

答案 0 :(得分:515)

每次覆盖方法时都使用它以获得两个好处。这样做是为了让您可以利用编译器检查来确保在您认为自己真正重写方法时。这样,如果您犯了一个错误拼写方法名称或者没有正确匹配参数的常见错误,您将收到警告,您的方法实际上并没有像您认为的那样覆盖。其次,它使您的代码更容易理解,因为当覆盖方法时更明显。

此外,在Java 1.6中,您可以使用它来标记方法何时实现具有相同优点的接口。我认为最好有一个单独的注释(如@Implements),但它总比没有好。

答案 1 :(得分:110)

我认为它最有用的是编译时提醒,方法的意图是覆盖父方法。举个例子:

protected boolean displaySensitiveInformation() {
  return false;
}

您经常会看到类似于上述方法的内容,它会覆盖基类中的方法。这是此类的重要实现细节 - 我们不希望显示敏感信息。

假设此方法在父类中更改为

protected boolean displaySensitiveInformation(Context context) {
  return true;
}

此更改不会导致任何编译时错误或警告 - 但它会完全更改子类的预期行为。

要回答您的问题:如果缺少超类中具有相同签名的方法指示错误,则应使用@Override注释。

答案 2 :(得分:46)

这里有很多好的答案,所以让我提供另一种方式来看待它......

编码时没有矫枉过正。键入@override不会花费任何费用,但如果拼写错误的方法名称或签名稍有错误,可能会节省大笔费用。

以这种方式思考:当你在这里导航并输入这篇文章时,你花了更多的时间,而不是在你的余生中输入@override;但它阻止的一个错误可以节省你的时间。

Java尽其所能确保您在编辑/编译时没有犯任何错误,这是解决整个类错误的几乎免费方式,这些错误在全面测试之外无法以任何其他方式阻止

你能想出一个更好的Java机制来确保当用户想要覆盖一个方法时,他实际上做了吗?

另一个简洁的效果是,如果你不提供注释,它将在编译时警告你,你不小心覆盖了父方法 - 如果你不打算这样做,这可能是重要的。

答案 3 :(得分:22)

我总是使用标签。这是一个简单的编译时标志,可以捕捉到我可能犯的小错误。

它会捕捉tostring()而不是toString()

之类的内容

小项目有助于大型项目。

答案 4 :(得分:18)

使用@Override注释充当编译时防范常见编程错误的保护措施。如果你有一个方法的注释你实际上没有覆盖超类方法,它将抛出一个编译错误。

最常见的情况是,当您将基类中的方法更改为具有不同的参数列表时。由于更改的方法签名,用于覆盖超类方法的子类中的方法将不再这样做。这有时会导致奇怪和意外的行为,尤其是在处理复杂的继承结构时。 @Override注释可以防止这种情况发生。

答案 5 :(得分:14)

要利用编译器检查,您应始终使用“覆盖注释”。但是不要忘记在重写接口方法时Java Compiler 1.5不允许这个注释。您可以使用它来覆盖类方法(抽象或不抽象)。

某些IDE,如Eclipse,甚至配置了Java 1.6运行时或更高版本,它们保持与Java 1.5的兼容性,并且不允许使用@override,如上所述。要避免这种行为,您必须转到:项目属性 - > Java编译器 - >选中“启用项目特定设置” - >选择“编译器合规性级别”= 6.0或更高版本。

如果基础是接口或类,我每次单独覆盖一个方法时都喜欢使用这个注释。

这可以帮助您避免一些典型的错误,因为当您认为您正在覆盖事件处理程序然后您看不到任何事情发生时。想象一下,您想要向某个UI组件添加事件侦听器:

someUIComponent.addMouseListener(new MouseAdapter(){
  public void mouseEntered() {
     ...do something...
  }
});

上面的代码编译并运行,但是如果你在someUIComponent中移动鼠标,那么“do something”代码会注意到run,因为实际上你并没有覆盖基本方法mouseEntered(MouseEvent ev)。您只需创建一个新的无参数方法mouseEntered()。如果您使用了@Override注释,那么您已经看到了编译错误,并且您没有浪费时间思考为什么您的事件处理程序没有运行。而不是那些代码。

答案 6 :(得分:8)

接口实现上的@Override不一致,因为在java中没有“覆盖接口”这样的东西。

接口实现上的@Override是没用的,因为在实践中它不会捕获编译无法捕获的错误。 实现者的覆盖实际上只做了一件事,只有一个很难实现的场景:如果你实现了一个接口和接口REMOVES方法,你将在编译时通知你应该删除未使用的实现。请注意,如果接口的新版本具有NEW或CHANGED方法,那么您显然会收到编译错误,因为您没有实现新的东西。

接口实现者的@Override永远不应该在1.6中被允许,并且由于eclipse遗憾地选择自动插入注释作为默认行为,我们会得到很多混乱的源文件。当读取1.6代码时,如果方法实际覆盖超类中的方法或仅实现接口,则无法从@Override注释中看到。

在实际覆盖超类中的方法时使用@Override很好。

答案 7 :(得分:8)

最好将它用于每个用作覆盖的方法,以及Java 6+,每个方法都用作接口的实现。

首先,它在编译时捕获像“hashcode()”而不是“hashCode()”的拼写错误。当真正的原因是你的代码永远不会被调用时,调试为什么你的方法的结果似乎与你的代码不匹配可能会令人费解。

此外,如果超类更改了方法签名,则旧签名的覆盖可能会“孤立”,留下令人困惑的死代码。 @Override注释将帮助您识别这些孤儿,以便修改它们以匹配新签名。

答案 8 :(得分:7)

它做的另一件事是它在阅读代码时更明显地改变了父类的行为。比可以帮助调试。

此外,在Joshua Block的书“Effective Java”(第2版)中,第36项提供了有关注释益处的更多细节。

答案 9 :(得分:7)

如果你经常发现自己压倒(非抽象)方法,你可能想看看你的设计。当编译器无法捕获错误时,它非常有用。例如,尝试覆盖ThreadLocal中的initValue(),我已经完成了。

在实现接口方法(1.6+功能)时使用@Override对我来说似乎有点矫枉过正。如果你有很多方法,其中一些方法会覆盖,有些方法则没有,那可能会再次设计不好(如果你不知道,你的编辑可能会显示哪个方法)。

答案 10 :(得分:7)

接口上的@Override实际上很有用,因为如果更改界面,将会收到警告。

答案 11 :(得分:6)

每当方法覆盖另一个方法,或者方法在接口中实现签名时。

@Override注释确保您确实覆盖了某些内容。如果没有注释,您可能会出现拼写错误或参数类型和数量的差异。

答案 12 :(得分:6)

在实现接口方法时使用@Override完全没有意义。在这种情况下使用它没有任何好处 - 编译器已经捕获了你的错误,所以它只是不必要的混乱。

答案 13 :(得分:5)

我到处都用它。 关于标记方法的工作主题,我让Eclipse为我做,所以,这不是额外的努力。

我对连续重构很虔诚....所以,我会用每一件小事让它变得更顺利。

答案 14 :(得分:5)

最好的方法是始终使用它(或让IDE为你填充)

@Override有用性是检测未在层次结构中报告的父类中的更改。 没有它,您可以更改方法签名并忘记更改其覆盖,使用@Override,编译器将为您捕获它。

这种安全网总是好的。

答案 15 :(得分:5)

我每次都用它。这是我可以用来快速弄清楚当我在一年内重新访问代码时会发生什么的更多信息,而且我已经忘记了我第一次想到的内容。

答案 16 :(得分:5)

  • 仅用于方法声明。
  • 表示带注释的方法 声明覆盖声明 在超级类型。

如果一直使用,它可以保护您免受大量恶意错误的侵害。

使用@Override注释来避免这些错误: (发现以下代码中的错误:)

public class Bigram {
    private final char first;
    private final char second;
    public Bigram(char first, char second) {
        this.first  = first;
        this.second = second;
    }
    public boolean equals(Bigram b) {
        return b.first == first && b.second == second;
    }
    public int hashCode() {
        return 31 * first + second;
    }

    public static void main(String[] args) {
        Set<Bigram> s = new HashSet<Bigram>();
        for (int i = 0; i < 10; i++)
            for (char ch = 'a'; ch <= 'z'; ch++)
                s.add(new Bigram(ch, ch));
        System.out.println(s.size());
    }
}

来源:Effective Java

答案 17 :(得分:3)

使用Override时要小心,因为之后你无法在starUML中进行逆向工程;首先制作uml。

答案 18 :(得分:2)

似乎这里的智慧正在发生变化。今天我安装了IntelliJ IDEA 9并注意到它的“missing @Override inspection”现在不仅捕获了实现的抽象方法,还实现了接口方法。在我的雇主的代码库和我自己的项目中,我一直习惯只使用@Override来实现前者 - 实现的抽象方法。然而,重新思考习惯,在两种情况下使用注释的优点都变得清晰。尽管更加冗长,但它确实可以防止脆弱的基类问题(不像C ++相关的例子那样严重),其中接口方法名称发生了变化,孤立了派生类中的潜在实现方法。

当然,这种情况大多是夸张的;派生类将不再编译,现在缺少重命名的接口方法的实现,今天可能会使用重命名方法重构操作来集中处理整个代码库。

鉴于IDEA的检查无法配置以忽略已实现的界面方法,今天我将改变我的习惯和我的团队的代码审查标准。

答案 19 :(得分:2)

注释@Override用于帮助检查开发人员是否覆盖父类或接口中的正确方法。当super的方法名称发生变化时,编译器可以通知该情况,这只是为了保持与super和子类的一致性。

顺便说一下,如果我们没有在子类中宣布注释@Override,但是我们覆盖了super的某些方法,那么该函数可以像@Override一样工作。但是当super的方法被更改时,此方法无法通知开发人员。因为它不知道开发人员的目的 - 覆盖超级方法或定义新方法?

因此,当我们想要覆盖该方法以使用多态时,我们最好在方法之上添加@Override。

答案 20 :(得分:1)

我尽可能地使用它来识别何时覆盖方法。如果你看一下Scala编程语言,他们也有一个override关键字。我发现它很有用。

答案 21 :(得分:0)

对我来说,@ Override确保我有正确的方法签名。如果我输入注释并且方法没有正确拼写,那么编译器会抱怨让我知道出错了。

答案 22 :(得分:0)

注释确实为编译器提供了有关代码的元数据,并且当我们覆盖任何基类方法时,在继承的情况下使用注释@Override。它只是告诉编译器你是重写方法。它可以避免我们可以做的一些常见错误,例如不遵循方法的正确签名或错误的方法名称等。因此,使用@Override注释是一个很好的做法。

答案 23 :(得分:0)

我认为最好在允许的情况下对@override进行编码。它有助于编码。但是,需要注意的是,对于ecipse Helios,无论是sdk 5还是6,都允许实现接口方法的@override注释。至于Galileo,无论是5还是6,都不允许@override注释。

答案 24 :(得分:0)

覆盖注释用于利用编译器,以检查您是否实际覆盖了父类中的方法。它用于通知您是否犯了错误拼写方法名称错误,错误未正确匹配参数

答案 25 :(得分:0)

简单 - 当您想要覆盖超类中存在的方法时,使用@Override注释来进行正确的覆盖。如果您没有正确覆盖它,编译器会发出警告。

答案 26 :(得分:0)

它允许你(好吧,编译器)在你重写的方法名称上使用了错误的拼写时捕获。