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年出版,到现在已经将 ...
随机推荐
- 最佳实践: 勿在 Servlet 中实现 SingleThreadModel
摘要 请不要实现 SingleThreadModel 接口.这种实践将导致 Web 容器创建多个 servlet 实例:即为每个用户创建一个实例.对于任何大小的应用程序,这种实践都将导致严重的性能问题 ...
- 这些年,我们一直追随的.NET
闲来无事,浏览自己的QQ空间,意外发现自己在13年1月份的发在QQ空间写的一片关于技术的随笔,觉得应该将其移到这里: 这些年,我们一直追随的.NET 前两天,意外地看到了.NET平台为异 ...
- Openshift 用户,角色和RBAC
OCP中的权限管理沿用的Kubernetes RBAC机制,授权模式主要取决于下面几个因数 Rules 针对主要对象的操作权限,比如建立Pod Sets of permitted verbs on a ...
- 为什么深度神经网络难以训练Why are deep neural networks hard to train?
Imagine you're an engineer who has been asked to design a computer from scratch. One day you're work ...
- 二十四种设计模式:代理模式(Proxy Pattern)
代理模式(Proxy Pattern) 介绍为其他对象提供一个代理以控制对这个对象的访问. 示例有一个Message实体类,某对象对它的操作有Insert()和Get()方法,用一个代理来控制对这个对 ...
- sftp子系统申请已拒绝 请确保ssh连接的sftp子系统设置有效
一.sftp子系统申请已拒绝,请确保ssh连接的sftp子系统设置有效 1.修改配置文件 [root@nulige ~]# vi /etc/ssh/sshd_config # override def ...
- saltstack之mount和umount的用法
线上很多服务器都需要挂载存储上的公共目录,并实现开机启动(/etc/fstab),比如web的静态文件共享目录,日志远程集中收集等. 一.批量挂载部分. 1.在node1上配置nfs服务器,有关nfs ...
- eclipse package explorer视图中怎么让default package不显示?
如下图所示:
- Java笔记8:Hibernate连接Oracle
1下载hibernate-3.6.0 Final.zip到任意目录,解压缩后得到hibernate目录 2下载slf4j-1.7.13.zip到任意目录,解压缩后得到slf4j-1.7.13 3操作数 ...
- 《深入理解Java虚拟机》笔记7
组内有人问我,她写的程序总是在短时间内就jvm异常. 另外,debug时候又可以正常通过,写的逻辑并不复杂, 只是用poi检索Excel.第一反应还是程序可能写的有问题, 也许写了一个jvm未预测的错 ...