Effective Java-第三章
第3章 对于所有对都通用的方法
尽管Object是一个具体类,但是设计它主要是为了扩展,它所有的非final方法(equals,hashCode,toString,clone和finalize)都有明确的通用约定,因为它们被设计成是要被覆盖的。任何一个类,它在覆盖这些方法的时候,都有责任遵守这些通用约定。如果不能做到这一点,其他依赖于这些约定的类(如HashMap和HashSet)就无法结合该类一起正常工作。
8. 覆盖equals时请遵守通用约定
如果累具有自己特有的“逻辑相等”概念(不同于对象等同的概念),而且超类还没有覆盖equals以实现期望的行为,这时我们就需要覆盖equals方法。
equals方法必须要遵守的通用约定:
- 自反性:对于任何非null的引用值x,x.equals(x)必须返回true;
- 对称性:对于任何非null的引用值x和y,当且仅当y.equals(x)返回true时,x.equals(y)必须返回true;
- 传递性:对于任何非null的引用值x,y和z,如果x.equals(y)返回true,并且y.equals(z)也返回true,那么x.equals(z)也必须返回true;
- 一致性:对于任何非null的引用值x和y,只要equals的比较操作在对象中所用的信息没有被修改,多次调用x.equals(y)就会一致地返回true,或者一致地返回false;
- 对于任何非null的引用值x,x.equals(null)必须返回false。
实现高质量equals方法的诀窍:
- 使用==操作符检查“参数是否为这个对象的引用”;
- 使用instanceof操作符检查“参数是否为正确的类型”;
- 把参数转换成正确的类型;
- 对于该类中的每个“关键域”,检查参数中的域是否与该对象中对应的域相匹配:(1)对于非float也不是double类型的基本类型,可以使用==操作符进行比较(2)对于对象引用域,可以递归调用equals方法(3)对于float域,使用Float.compare方法,对于double域,使用Double.compare方法(4)对于数组域则把以上这些指定原则应用到每个元素上或利用Arrays.equals方法
域的比较顺序可能会影响到equals方法的性能,为了获得最佳的性能,颖最先比较最有可能不一致的域,或者是开销最低的域。
9. 覆盖equals时总要覆盖hashCode
一个很常见的错误根源在于没有覆盖hashCode方法,在每个覆盖了equals方法的类中,也必须覆盖hashCode方法,如果不这样做的话,就会违反Object.hashCode的通用约定,从而导致该类无法结合所有基于散列的集合一起正常工作,这样的集合博阿凯HashMap,HashSet和Hashtable。
约定:
- 在应用程序的执行期间,只要对象的equal方法的比较操作所用到的信息没有被修改,那么对这个同一个对象调用多次,hashCode方法都必须始终如一返回同一个整数。在同一应用程序的多次执行过程中,每次执行所返回的整数可以不一致。
- 如果两个对象根据equals方法比较是相等,那么调用这两个对象中任意一个对象的hashCode方法都必须产生同样的整数结果。(相等的对象必须具有相等的散列码)
- 如果两个对象根据equals方法比较是不相等的,那么调用这两个对象中任意一个对象的hashCode方法,则不一定要产生不同的整数结果,但是给不相等对象产生截然不同的整数结果,有可能提高散列表的性能。
一个号的散列函数通常应该是“为不相等的对此产生不相等的散列码”。散列函数应该把集合中不相等的实例均匀分布到所有可能的散列值上。想要完全达到这种理想的情形是非常困难的,幸运的是,相对接近这种理想情形则并不太困难:
- 把某个非零的常量值,比如说1,保存在一个名为result的int类型的变量中。
- 对于对象中每个关键域f(指equals方法中涉及的每个域),计算int类型的散列码c。
- 按照result = 31 * result + c公式,把散列码c合并到result中。
- 返回result。
其中计算域f的int类型的散列码,有如下的几种场景:
(1)如果该域是boolean类型,则计算(f ? 1 : 0);
(2)如果是byte,char,short或int类型,则计算(int)f;
(3)如果是long,计算(int)(f^f>>>32);
(4)如果是float,则计算Float.flaotToIntBits(f);
(5)如果是double,先计算Double.doubleToLongBits(f)返回long类型,然后按照(3)处理;
(6)如果是对象引用,递归调用对象的hashCode方法;
(7)如果是数组,对每个元素单独处理,或调用Arrays.hashCode方法。
具体可以参考Arrays类里面很多hashCode()方法;
10. 始终要覆盖toString
虽然Object同了toString方法的一个实现,返回的字符串通常并不是类的用户所期望看到的。它包含一个类的名称,以及一个@符号,接着是散列码的无符号16禁止表示法。
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
建议所有的子类都覆盖这个方法。
11. 谨慎地覆盖clone
Cloneable接口的目的是作为对象允许克隆。
既然Cloneable并没有包含任何方法,那么它到底有什么作用呢?它决定了Object中受保护的clone方法实现的行为:如果一个类实现了Cloneable,Object的clone方法就返回该对象的逐域拷贝,否则抛出异常CloneNotSupportedException。

实现接口的版本:

12. 考虑实现Comparable接口
compareTo方法并没有在Object中声明。它是Comparable接口中唯一的方法。
类实现了Comparable接口,就表明它的实例具有内在的排序关系。
违反compareTo约定的类也会破坏其他依赖于比较关系的类。依赖于比较关系的类包括有序集合类TreeSet和TreeMap,以及工具类Collections和Arrays,它们内部包含有搜索和排序算法。
x.参考文档
《Effective Java中文版 第2版》
Effective Java-第三章的更多相关文章
- [Effective Java]第三章 对所有对象都通用的方法
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
- 对于所有对象都通用方法的解读(Effective Java 第三章)
这篇博文主要介绍覆盖Object中的方法要注意的事项以及Comparable.compareTo()方法. 一.谨慎覆盖equals()方法 其实平时很少要用到覆盖equals方法的情况,没有什么特殊 ...
- 《Effective Java 第三版》新条目介绍
版权声明:本文为博主原创文章,可以随意转载,不过请加上原文链接. https://blog.csdn.net/u014717036/article/details/80588806前言 从去年的3月份 ...
- EFFECTIVE JAVA 第十一章 系列化
EFFECTIVE JAVA 第十一章 系列化(将一个对象编码成一个字节流) 74.谨慎地实现Serializable接口 *实现Serializable接口付出的代价就是大大降低了“改变这个类 ...
- “全栈2019”Java第三章:安装开发工具IntelliJ IDEA
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- Think in Java 第三章操作符
Think in Java 第三章操作符 赋值 对象赋值 我们真正操作的是对对象的引用.所以倘若"将一个对象赋值给另一个对象",实际上是将"引用"从一个地方 ...
- Effective Java 第三版——3. 使用私有构造方法或枚类实现Singleton属性
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——10. 重写equals方法时遵守通用约定
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——14.考虑实现Comparable接口
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——21. 为后代设计接口
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
随机推荐
- Oracle SQL执行缓慢的原因以及解决方案
以下的文章抓哟是对Oracle SQL执行缓慢的原因的分析,如果Oracle数据库中的某张表的相关数据已是2亿多时,同时此表也创建了相关的4个独立的相关索引.由于业务方面的需要,每天需分两次向此表中 ...
- Android 卡顿优化 3 布局优化 工具 Hierarchy Viewer
欲善其事, 先利其器. 分析布局, 就不得不用到Hierarchy Viewer了. 本文工具使用皆以GithubApp的详情界面RepoDetailActivity为例说明. 为了不影响阅读体验, ...
- 游戏用户接口设计的一些小原则(摘自 game coding complete)
1.没有坏之前不要修理 2.简单的操作却有非常复杂的结果时,要小心设计. 3.记得给玩家反馈. 4.玩家不知道该功能,可能就根本不会用这个功能. 5.观察并持续改进.(给不熟悉该设计的人玩,站在他们后 ...
- JavaScript 中的不可变对象(Immutable Objects)
默认情况下,JavaScript 中的对象是可变的.我们可以更改原始值(字符串,数字等)和对象.我们来看看这个对象: let obj = { num: , obj: { content: " ...
- scrapy-splash抓取动态数据例子八
一.介绍 本例子用scrapy-splash抓取界面网站给定关键字抓取咨询信息. 给定关键字:个性化:融合:电视 抓取信息内如下: 1.资讯标题 2.资讯链接 3.资讯时间 4.资讯来源 二.网站信息 ...
- Spring MVC入门Demo
1 参考http://blog.csdn.net/haishu_zheng/article/details/51490299,用第二种方法创建一个名为springmvcdemo的Maven工程. 2 ...
- Java中的SPI(Service Provider Interface)
转自:http://singleant.iteye.com/blog/1497259 最近看到公司的一些框架和之前看到的开源的一些框架的一些服务发现和接入都采用了java的spi机制. 所以简单的总结 ...
- 快速实现一个生产者-消费者模型demo
package jesse.test1; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.Blo ...
- [Android Pro] service中显示一个dialog 或者通过windowmanage显示view
转载: http://blog.csdn.net/huxueyan521/article/details/8954844 通过windowmananger来在窗口上添加view的时候,需要设置aler ...
- MVC入门教程二[第一个小Demo](转载)
本文目标 1.了解"模型"."视图"."控制器"的创建.调试和使用过程. 本文目录 1.创建模型 2.创建视图 3.创建控制器 4.调试 5 ...