Effective Java 第三版——40. 始终使用Override注解
Tips
《Effective Java, Third Edition》一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将近8年的时间,但随着Java 6,7,8,甚至9的发布,Java语言发生了深刻的变化。
在这里第一时间翻译成中文版。供大家学习分享之用。

40. 始终使用Override注解
Java类库包含几个注解类型。对于典型的程序员来说,最重要的是@Override。此注解只能在方法声明上使用,它表明带此注解的方法声明重写了父类的声明。如果始终使用这个注解,它将避免产生大量的恶意bug。考虑这个程序,在这个程序中,类Bigram表示双字母组合,或者是有序的一对字母:
// Can you spot the bug?
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<>();
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());
}
}
主程序重复添加二十六个双字母组合到集合中,每个双字母组合由两个相同的小写字母组成。 然后它会打印集合的大小。 你可能希望程序打印26,因为集合不能包含重复项。 如果你尝试运行程序,你会发现它打印的不是26,而是260。它有什么问题?
显然,Bigram类的作者打算重写equals方法(条目 10),甚至记得重写hashCode(条目 11)。 不幸的是,我们倒霉的程序员没有重写equals,而是重载它(条目 52)。 要重写Object.equals,必须定义一个equals方法,其参数的类型为Object,但Bigram的equals方法的参数不是Object类型的,因此Bigram继承Object的equals方法,这个equals方法测试对象的引用是否是同一个,就像==运算符一样。 每个祖母组合的10个副本中的每一个都与其他9个副本不同,所以它们被Object.equals视为不相等,这就解释了程序打印260的原因。
幸运的是,编译器可以帮助你找到这个错误,但只有当你通过告诉它你打算重写Object.equals来帮助你。 要做到这一点,用@Override注解Bigram.equals方法,如下所示:
@Override public boolean equals(Bigram b) {
return b.first == first && b.second == second;
}
如果插入此注解并尝试重新编译该程序,编译器将生成如下错误消息:
Bigram.java:10: method does not override or implement a method
from a supertype
@Override public boolean equals(Bigram b) {
^
你会立刻意识到你做错了什么,在额头上狠狠地打了一下,用一个正确的(条目 10)来替换出错的equals实现:
@Override public boolean equals(Object o) {
if (!(o instanceof Bigram))
return false;
Bigram b = (Bigram) o;
return b.first == first && b.second == second;
}
因此,应该在你认为要重写父类声明的每个方法声明上使用Override注解。 这条规则有一个小例外。 如果正在编写一个没有标记为抽象的类,并且确信它重写了其父类中的抽象方法,则无需将Override注解放在该方法上。 在没有声明为抽象的类中,如果无法重写抽象父类方法,编译器将发出错误消息。 但是,你可能希望关注类中所有重写父类方法的方法,在这种情况下,也应该随时注解这些方法。 大多数IDE可以设置为在选择重写方法时自动插入Override注解。
大多数IDE提供了是种使用Override注解的另一个理由。 如果启用适当的检查功能,如果有一个方法没有Override注解但是重写父类方法,则IDE将生成一个警告。 如果始终使用Override注解,这些警告将提醒你无意识的重写。 它们补充了编译器的错误消息,这些消息会提醒你无意识重写失败。 IDE和编译器,可以确保你在任何你想要的地方和其他地方重写方法,万无一失。
Override注解可用于重写来自接口和类的方法声明。 随着default默认方法的出现,在接口方法的具体实现上使用Override以确保签名是正确的是一个好习惯。 如果知道某个接口没有默认方法,可以选择忽略接口方法的具体实现上的Override注解以减少混乱。
然而,在一个抽象类或接口中,值得标记的是你认为重写父类或父接口方法的所有方法,无论是具体的还是抽象的。 例如,Set接口不会向Collection接口添加新方法,因此它应该在其所有方法声明中包含Override注解以确保它不会意外地向Collection接口添加任何新方法。
总之,如果在每个方法声明中使用Override注解,并且认为要重写父类声明,那么编译器可以保护免受很多错误的影响,但有一个例外。 在具体的类中,不需要注解标记你确信可以重写抽象方法声明的方法(尽管这样做也没有坏处)。
Effective Java 第三版——40. 始终使用Override注解的更多相关文章
- Effective Java 第三版——12. 始终重写 toString 方法
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- 《Effective Java 第三版》目录汇总
经过反复不断的拖延和坚持,所有条目已经翻译完成,供大家分享学习.时间有限,个别地方翻译得比较仓促,希望有疑虑的地方指出批评改正. 第一章简介 忽略 第二章 创建和销毁对象 1. 考虑使用静态工厂方法替 ...
- 《Effective Java 第三版》新条目介绍
版权声明:本文为博主原创文章,可以随意转载,不过请加上原文链接. https://blog.csdn.net/u014717036/article/details/80588806前言 从去年的3月份 ...
- Effective Java 第三版——10. 重写equals方法时遵守通用约定
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——11. 重写equals方法时同时也要重写hashcode方法
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——39. 注解优于命名模式
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——44. 优先使用标准的函数式接口
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——1. 考虑使用静态工厂方法替代构造方法
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——3. 使用私有构造方法或枚类实现Singleton属性
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
随机推荐
- 理解WebKit和Chromium: Android 4.4 上的Chromium WebView
转载请注明原文地址:http://blog.csdn.net/milado_nju ## 概述 相信读者已经注意到了,在最新的Android 4.4 Kitkat版本中,原本基于Android Web ...
- Django介绍、安装配置、基本使用、Django用户注册例子
Django介绍 Django 是由 Python 开发的一个免费的开源网站框架,可以用于快速搭建高性能,优雅的网站 DjangoMTV的思想 没有controller ...
- Linux进程实践(4) --wait避免僵尸进程
Wait的背景 当子进程退出的时候,内核会向父进程发送SIGCHLD信号,子进程的退出是个异步事件(子进程可以在父进程运行的任何时刻终止) 子进程退出时,内核将子进程置为僵尸状态,这个进程称为僵尸进程 ...
- AngularJS进阶(三十一)AngularJS项目开发技巧之获取模态对话框中的组件ID
AngularJS项目开发技巧之获取模态对话框中的组件ID 需求 出于项目开发需求,需要实现的业务逻辑是:药店端点击查看"已发货""已收货"订单详情时,模块弹出 ...
- Linux 安装python爬虫框架 scrapy
Linux 安装python爬虫框架 scrapy http://scrapy.org/ Scrapy是python最好用的一个爬虫框架.要求: python2.7.x. 1. Ubuntu14.04 ...
- 【翻译】在Ext JS和Sencha Touch中创建自定义布局
原文:Creating Custom Layouts in Ext JS and Sencha Touch 布局系统是Sencha框架中最强大和最独特的一部分.布局会处理应用程序中每个组件的大小和位置 ...
- Which is Better: Forms Servlet or Socket Mode?
URL:http://blogs.oracle.com/stevenChan/2009/06/which_is_better_forms_servlet_or_socket_mode.html Man ...
- 集群通信组件tribes之通道拦截器
拦截器应该可以说是一个很经典的设计模式,它有点类似于过滤器,当某信息从一个地方流向目的地的过程中,可能需要统一对信息进行处理,如果考虑到系统的可扩展性和灵活性通常就会使用拦截器模式,它就像一个个关卡被 ...
- C++中const的实现机制深入分析
via:http://www.jb51.net/article/32336.htm C语言以及C++语言中的const究竟表示什么?其具体的实现机制又是如何实现的呢?本文将对这两个问题进行一些分析,需 ...
- Xcode模拟器中无法播放音频文件的原因分析
在本猫的Mac Mini上开发iOS app,发现当执行到播放音频的代码时,发生错误,log如下: 2015-10-05 07:22:17.122 LearnSpriteBuilder[10321:5 ...