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年出版,到现在已经将 ... 
随机推荐
- 【转】Gvim配置(Windows and Linux)for C++
			转载地址:http://blog.csdn.net/onepiecehuiyu/article/details/8934366 http://mawenhao19930620.blog.163.com ... 
- 《Go语言实战》笔记之第三章 ----包
			原文地址: http://www.niu12.com/article/10 ####包 所有的.go 文件,除了空行和注释,都应该在第一行声明自己所属的包. 每个包都在一个单独的目录里. 不能把多个包 ... 
- 如何在sublime3项目设置中设置python模块的搜索路径?ImportError: No module named *的解决办法
			问题:之前使用pycharm,用的挺溜,但是电脑配置实在不争气,pycharm启动久了,耗去大量内存,导致运行起来越来越慢,于是转向使用sublime text. 把项目从pycharm切换到subl ... 
- xss测试用例小结
			<script>alert("跨站")</script> (最常用) <img scr=javascript:alert("跨站" ... 
- FPGA作为从机与STM32进行SPI协议通信---Verilog实现
			一.SPI协议简要介绍 SPI,是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接口.SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用 ... 
- 摄像头模组光学CRA(chief ray angle)
			http://blog.csdn.net/sylorchen/article/details/54618874 Lens CRA CRA(Chief Ray Angle):从镜头的传感器一侧,可以聚焦 ... 
- 教你如何搭建vue项目
			笔者工作也有一些时间,需要用vue写项目时也总是项目组长已经把项目搭建好了, 偶尔心血来潮想试着自己搭建一个vue项目 我们搭建vue项目呢主要是用到了vue-cli来搭建,但是前提是必须要已经安装好 ... 
- linux经常使用文字处理命令总结
			linux grep命令 作用 Linux系统中grep命令是一种强大的文本搜索工具,它能使用正則表達式搜索文本,并把匹 配的行打印出来.grep全称是Global Regular Expressio ... 
- linux mysql 更改MySQL数据库目录位置
			MySQL默认的数据文件存储目录为/var/lib/mysql.假如要把目录移到/home/data下需要进行下面几步: 1.home目录下建立data目录 cd /home mkdir data 2 ... 
- iOS真机调试 for Xcode 5
			由于Xcode5的到来,关于iOS软件进行真机调试方面,有了一些变化,苹果在Xcode 5中修改了一些规则,一方面是阻止以往破解的方式进行调试(免证书).另一方面是添加了自动生成证书的功能特性,来加快 ... 
