使用Java @Override
注释的最佳实践是什么?为什么?
使用@Override
注释标记每个重写方法似乎有点过分.是否有某些编程情况需要使用@Override
和其他不应该使用的@Override
?
每次覆盖一个方法时使用它有两个好处.这样做是为了让您可以利用编译器检查来确保在您认为自己真正重写方法时.这样,如果您犯了一个错误拼写方法名称或者没有正确匹配参数的常见错误,您将被警告您方法实际上并没有像您认为的那样覆盖.其次,它使您的代码更容易理解,因为当覆盖方法时更加明显.
此外,在Java 1.6中,您可以使用它来标记方法何时实现具有相同优点的接口.我认为最好有一个单独的注释(比如@Implements
),但它总比没有好.
我认为它作为编译时提醒最有用,该方法的意图是覆盖父方法.举个例子:
protected boolean displaySensitiveInformation() { return false; }
您经常会看到类似于上述方法的内容,它会覆盖基类中的方法.这是此类的重要实现细节 - 我们不希望显示敏感信息.
假设此方法在父类中更改为
protected boolean displaySensitiveInformation(Context context) { return true; }
此更改不会导致任何编译时错误或警告 - 但它会完全更改子类的预期行为.
要回答您的问题:如果缺少超类中具有相同签名的方法指示错误,则应使用@Override注释.
这里有很多好的答案,所以让我提供另一种方式来看待它......
编码时没有矫枉过正.键入@override不会花费任何费用,但如果拼写错误的方法名称或签名稍有错误,可能会节省大量成本.
这样考虑一下:当你在这里导航并输入这篇文章的时候,你几乎花了更多的时间,而不是在你的余生中用@foreride打字; 但它阻止的一个错误可以节省你的时间.
Java那样所能,以确保你没有在编辑犯任何错误/编译时间,这是解决整个类是无法预防以任何其他方式全面测试之外的失误几乎免费的方式.
你能想出一个更好的Java机制来确保当用户想要覆盖一个方法时,他确实做到了吗?
另一个整齐的效果是,如果你不提供注解它会警告你在编译的时候,你不小心推翻父方法 - 这可能是显著,如果你不打算这样做.
我总是使用标签.这是一个简单的编译时标志,可以捕获我可能犯的小错误.
它会捕捉到的东西tostring()
而不是toString()
小事情有助于大型项目.
使用@Override
注释充当编译时防范常见编程错误的保护措施.如果你在一个方法上没有实际覆盖超类方法的注释,它将抛出一个编译错误.
最常见的情况是,当您将基类中的方法更改为具有不同的参数列表时.由于更改的方法签名,用于覆盖超类方法的子类中的方法将不再这样做.这有时会导致奇怪和意外的行为,尤其是在处理复杂的继承结构时.该@Override
注释保障反对这一点.
要利用编译器检查,您应始终使用"覆盖注释".但是不要忘记在重写接口方法时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"代码会注意运行,因为实际上你没有覆盖基本方法mouseEntered(MouseEvent ev)
.您只需创建一个新的无参数方法mouseEntered()
.如果您使用了@Override
注释,那么您已经看到了编译错误,并且您没有浪费时间思考为什么您的事件处理程序没有运行,而不是代码.
最好将它用于每个用作覆盖的方法,以及Java 6+,每个方法都用作接口的实现.
首先,它在编译时捕获像" hashcode()
"而不是" hashCode()
"的拼写错误.当真正的原因是你的代码从未被调用时,调试为什么你的方法的结果似乎与你的代码不匹配可能会令人困惑.
此外,如果超类更改了方法签名,则旧签名的覆盖可能会"孤立",留下令人困惑的死代码.该@Override
注释将帮助您确定这些孤儿,让他们可以被修改,以符合新的签名.
@Override在接口实现上是不一致的,因为在java中没有"覆盖接口"这样的东西.
接口实现上的@Override 是无用的,因为在实践中它不会捕获编译无法捕获的错误.实现者的覆盖实际上只做了一件事,只有一个很难实现的场景:如果你实现了一个接口和接口REMOVES方法,你将在编译时通知你应该删除未使用的实现.请注意,如果接口的新版本具有NEW或CHANGED方法,您显然会得到编译错误,因为您没有实现新的东西.
接口实现者的@Override永远不应该在1.6中被允许,并且由于eclipse遗憾地选择将注释自动插入为默认行为,因此我们得到了大量杂乱的源文件.当读取1.6代码时,如果方法实际覆盖超类中的方法或仅实现接口,则无法从@Override注释中看到.
实际覆盖超类中的方法时使用@Override很好.
如果您经常发现自己重写(非抽象)方法,那么您可能需要查看一下您的设计.当编译器无法捕获错误时,它非常有用.例如,尝试覆盖ThreadLocal中的initValue(),我已经完成了.
在实现接口方法(1.6+功能)时使用@Override对我来说似乎有点矫枉过正.如果你有一些方法,其中一些方法覆盖而有些方法没有覆盖,那可能是糟糕的设计(如果你不知道,你的编辑可能会显示哪个是哪个).
接口上的@Override实际上很有帮助,因为如果更改界面,将会收到警告.
它做的另一件事是它在阅读代码时更明显地改变了父类的行为.比可以帮助调试.
此外,在Joshua Block的书"Effective Java"(第2版)中,第36项提供了有关注释益处的更多细节.
每当方法覆盖另一个方法,或者方法在接口中实现签名时.
该@Override
注解向你保证,你实际上覆盖的东西一样.如果没有注释,您可能会出现拼写错误或参数类型和数量的差异.
在实现接口方法时使用@Override完全没有意义.在这种情况下使用它没有任何好处 - 编译器已经捕获了你的错误,所以它只是不必要的混乱.
我每次都用它.我可以使用更多信息来快速弄清楚当我在一年内重新访问代码时发生了什么,我忘记了第一次想到的内容.
最好的方法是始终使用它(或让IDE为您填充)
@Override有用性是检测未在层次结构中报告的父类中的更改.没有它,您可以更改方法签名并忘记更改其覆盖,使用@Override,编译器将为您捕获它.
这种安全网总是很好.
我到处都用它.关于标记方法的工作主题,我让Eclipse为我做,所以,这不是额外的努力.
我对连续重构很虔诚....所以,我会用每一件小事让它变得更加顺利.
仅用于方法声明.
指示带注释的方法声明会覆盖超类型中的声明.
如果使用一致,它可以保护您免受大量恶意错误的侵害.
使用@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) { Sets = new HashSet (); 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()); } }
来源:有效的Java