第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方法的诀窍:

  1. 使用==操作符检查“参数是否为这个对象的引用”;
  2. 使用instanceof操作符检查“参数是否为正确的类型”;
  3. 把参数转换成正确的类型;
  4. 对于该类中的每个“关键域”,检查参数中的域是否与该对象中对应的域相匹配:(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. 把某个非零的常量值,比如说1,保存在一个名为result的int类型的变量中。
  2. 对于对象中每个关键域f(指equals方法中涉及的每个域),计算int类型的散列码c。
  3. 按照result = 31 * result + c公式,把散列码c合并到result中。
  4. 返回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-第三章的更多相关文章

  1. [Effective Java]第三章 对所有对象都通用的方法

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

  2. 对于所有对象都通用方法的解读(Effective Java 第三章)

    这篇博文主要介绍覆盖Object中的方法要注意的事项以及Comparable.compareTo()方法. 一.谨慎覆盖equals()方法 其实平时很少要用到覆盖equals方法的情况,没有什么特殊 ...

  3. 《Effective Java 第三版》新条目介绍

    版权声明:本文为博主原创文章,可以随意转载,不过请加上原文链接. https://blog.csdn.net/u014717036/article/details/80588806前言 从去年的3月份 ...

  4. EFFECTIVE JAVA 第十一章 系列化

    EFFECTIVE  JAVA  第十一章  系列化(将一个对象编码成一个字节流) 74.谨慎地实现Serializable接口 *实现Serializable接口付出的代价就是大大降低了“改变这个类 ...

  5. “全栈2019”Java第三章:安装开发工具IntelliJ IDEA

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  6. Think in Java 第三章操作符

    Think in Java 第三章操作符 赋值 对象赋值 ​ 我们真正操作的是对对象的引用.所以倘若"将一个对象赋值给另一个对象",实际上是将"引用"从一个地方 ...

  7. Effective Java 第三版——3. 使用私有构造方法或枚类实现Singleton属性

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  8. Effective Java 第三版——10. 重写equals方法时遵守通用约定

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  9. Effective Java 第三版——14.考虑实现Comparable接口

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  10. Effective Java 第三版——21. 为后代设计接口

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

随机推荐

  1. AMBA AHB总线

    Advanced Microcontroller Bus Architecture, 即AMBA,是ARM公司提出的总线规范,被很多SoC设计所采用,常用的实现有AHB(Advanced High-P ...

  2. 对Storm ETL的初步思考

    ETL简介 ETL,是英文 Extract-Transform-Load 的缩写,用来描述将数据从来源端经过萃取(extract).转置(transform).加载(load)至目的端的过程. ETL ...

  3. [Todo]非常好的免费IT书籍资源 & Github排名

    今天看github排名,看到排在第二位的是免费书籍: https://github.com/vhf/free-programming-books/blob/master/free-programmin ...

  4. python 协程的学习记录

    协程是个子程序,执行过程中,内部可中断,然后转而执行别的子程序,在适当的时候再返回来接着执行 从句法上看,协程与生成器类似,都是定义体中包含 yield 关键字的函数.可是,在协程中,yield 通常 ...

  5. Linux 调度器发展简述

    引言 进程调度是操作系统的核心功能.调度器只是是调度过程中的一部分,进程调度是非常复杂的过程,需要多个系统协同工作完成.本文所关注的仅为调度器,它的主要工作是在所有 RUNNING 进程中选择最合适的 ...

  6. Python 面试中 8 个必考问题(转载)

    Python 面试中 8 个必考问题 1.下面这段代码的输出结果是什么?请解释. def extendList(val, list=[]): list.append(val) return list ...

  7. [Android Pro] 查看 keystore文件的签名信息 和 检查apk文件中的签名信息

    1: 查看 keystore文件的签名信息 keytool -list -v -keystore keystoreName -storepass keystorePassword 2: 检查apk文件 ...

  8. Microsoft Visual C++ Redistributable Package下载

    温馨提示: 1.目前,很多程序软件正常运行需要VC++库的支持,因此,博主在此做了一个合集,方便大家下载: 2.有需要的朋友请根据自己需要下载,博主所提供的下载地址均是微软官网的,请放心下载: 3.如 ...

  9. PHP的抽象类、接口的区别和选择[转载]

    区别: 1.对接口的使用是通过关键字implements.对抽象类的使用是通过关键字extends.当然接口也可以通过关键字extends继承. 2.接口中不可以声明成员变量(包括类静态变量),但是可 ...

  10. vue - config(dev.env.js和prov.env.js)

    描述:配置产品模式.打包模式:开发还是打包,以最佳运行(不配置则有一个大大的Warning!!!) 官网:https://www.webpackjs.com/concepts/mode/