第八条:覆盖equals时请遵守通用约定
==是物理相等
equals是逻辑相等
因为每个类的实例对象本质上都是唯一的 ,利用物理相等(==)是指一个实例只能相等于它自己。
利用逻辑相等是(equals)指 一个实例是否和另一个实例的某些关键域相等,从而来判断这两实例是否相等。
Object类的equals方法的实现:物理相等的话就逻辑相等。
什么时候不需要覆盖Object类的equals方法?
1.希望这个类的实例只能和自身相等,不覆盖equals方法,只继承Object类的equals方法。
我们比较这个类的实例对象是否相等,无论是使用 == 或者equals 实际上都是 进行物理相等的判断。
2.这个类的超类已经覆盖了Object类的equals方法,并且这个类继承超类的equals方法,对于它自身来说也是合适的,这时不覆盖equals方法。
例如:Set实现类都继承了AbstractSet类的equals方法,List实现类都继承了AbstractList类的equals方法,Map实现类都继承了AbstractMap类
的equals方法。
3.确定这个类的equals方法永远不会被调用时。
什么时候需要覆盖Object类的equals方法?
当一个类需要自己的特有的“逻辑相等”时,例如我们希望两个实例的某些关键域相等时,我们就认为它们两者是逻辑上相等的,调用equals方法就返回true。
如果不覆盖equals方法,继承Object类的equals方法,实际上进行的物理相等的判断,即一个实例只能和它自身相等。
例如:一些“值类”,如Integer,Date,String等,这些类我们在调用它们的equals方法时,希望只要两个实例的关键域相等,就返回true,而不是两个实例
是同一个实例时再返回true。而且这些类的equals方法必须被覆盖,从而在作为Map集合的key,或者Set集合的元素时出现符合预期的结果,因为它们的equals
方法会被调用来判断两个实例是否逻辑相等。
但是对于一些实例受控的类,如单例类,枚举类,这些类就不需要覆盖equals方法了。
正确覆盖equals方法,需要遵守它的通用约定:
1.自反性: x.equals(x) 必须返回true 。实例自身必然逻辑相等。
2.对称性: x.equals(y) 与 y.equals(x) 返回结果应该相同,同为true或者同为false。
3.传递性: x.equals(y)返回true,y.equals(z)返回true,则x.equals(z)应该返回true。
4.一致性: 只要比较的实例对象的关键属性值没有改变 ,那么无论调用多少次equals方法返回的结果都应该相同,一致。
5.对于非null的x实例,x.equals(null) 永远返回false。
上面的五条约定,十分重要。有许多类,包括所有的集合类在内,都依赖于传递给它们的实例对象是否遵守了equals约定。
结合所有的约定需求,得到实现高质量equals方法的诀窍:
1.使用==操作符检查“参数对象的引用是否是调用对象”的相同引用。如果是,返回true。
2.使用instanceof操作符检查参数对象的类型是否正确。这里的类型正确,一般是指验证参数对象的类型是否是当前类。有些情况
也可以在当前类实现的接口的其他实现类,之间进行比较。
3.把参数对象转化为正确的类型。因为已经经过instanceof类型检查过了,类型转化可以确保成功。
4.对于该类中的每个“关键”域,检查参数对象中域是否与当前对象中对应的域相匹配。
如果上面的测试全部成功,就返回true,否则就返回false。
其中对于既不是float也不是double类型的基本类型域,可以直接使用==操作符进行比较,对于float类型的域,使用Float.compare方法,对于
double类型的域,使用Double.compare方法。对于引用类型的域,调用引用类型的equals方法进行比较。
当一个类的equals方法完成时,应该明确:它是否是对称的,传递的,一致的? 应该写测试代码去进行测试。
还要铭记一下告诫:
1.覆盖equals方法时总要覆盖hashCode方法。(第九条)
2.不要企图让equals方法太过智能。
3.不要把参数Object类型 换成任何其他类型。因为Object类提供的equals方法的参数类型就是Object,如果把参数Object类型换成其他类型,
就变成了equals方法的重载,而不是equals方法的重写。 所以可以添加@Override注解 来避免这种错误。
第八条:覆盖equals时请遵守通用约定的更多相关文章
- 第8条:覆盖equals时请遵守通用约定
第8条:覆盖equals时请遵守通用约定 引言:尽管Object是一个具体类,但是设计它主要是为了拓展.它所有的非final方法(equals.hashCode.toString.clone和fina ...
- Item 8 覆盖equals时请遵守通用约定
在覆盖equals方法的时候,你必须要遵守它的通用约定,不遵守,写出来的方法,会出现逻辑错误.下面是约定的内容: equals方法实现了等价关系: 自反性.对于任何非null的引用值,x.eq ...
- 覆盖equals时请遵守通用约定
Object类中非final修饰的方法有equals().hashCode().toString().finalize().clone()1.equals()方法不需要被覆盖的情况:1)实例化的对象只 ...
- 【Effective Java】4、覆盖equals时请遵守通用约定
package cn.xf.cp.ch02.item8.transitivity; public class Point { private final int x; private final in ...
- 第10项:重写equals时请遵守通用约定
重写equals方法看起来似乎很简单,但是有许多重写方式会导致错误,而且后果非常严重.最容易避免这类问题的办法就是不覆盖equals方法,在这种情况下,类的每个实例都只能与它自身相等.如果满足了以 ...
- 覆盖equals方法时请遵守通用约定
覆盖equals方法时请遵守通用约定 覆盖equals方法看起来很简单,但是有许多覆盖方式会导致错误,并且后果很严重.最容易避免这种类问题的方法就是不覆盖equals方法,在这种情况下,类的每个实 ...
- EffectiveJava(8)覆盖equals是要遵守的约定
覆盖equals是要遵守的约定 1.覆盖种类: -类的每个1实例本质上都是唯一的 -不关心类是否提供了"逻辑相等"的测试功能(Random测试是否能随机相同数字) -超类已经覆盖了 ...
- 重写equals时,遵守的规定
0 正确的equals方法 public class MyClass { // 主要属性1 private int primaryAttr1; // 主要属性2 private int prima ...
- 第8条:覆盖equals时遵守通用约定
如果不需要覆盖equals方法,那么就无需担心覆盖equals方法导致的错误. 什么时候不需要覆盖equals方法? 1.类的每个实例本质上是唯一的. 例如对于Thread,Object提供的equa ...
随机推荐
- [SCOI2007]降雨量
ST表,再大力讨论一下(因为lower_bound和upper_bound,WA了一次) # include <bits/stdc++.h> # define RG register # ...
- Java的深拷贝和浅拷贝
关于Java的深拷贝和浅拷贝,简单来说就是创建一个和已知对象一模一样的对象.可能日常编码过程中用的不多,但是这是一个面试经常会问的问题,而且了解深拷贝和浅拷贝的原理,对于Java中的所谓值传递或者引用 ...
- tp5.带标签的缓存 创建和清除 测试
原文:http://www.upwqy.com/details/24.html 测试设置了标签的缓存的获取方式 和清除标签缓存. 有时候我们可能会对同类型的一些数据做统一缓存.和统一清除更新处理. 那 ...
- 关系型数据库工作原理-事务管理(二)(翻译自Coding-Geek文章)
本文翻译自Coding-Geek文章:< How does a relational database work>. 原文链接:http://coding-geek.com/how-dat ...
- HttpSessionActivationListener序列化与反序列化
一.序列化与反序列化 1.什么是序列化 把对象转化位字节序列的过程称为序列化(保存到硬盘,持久化) 把字节序列转化位对象的过程称为反序列化(存放于内存) 2.序列化的用途 把对象的字节序列永久保存到硬 ...
- NancyFX 第六章 视图引擎
正如其他的Web工具包,Nancy也有视图的概念,用来描述在浏览器上看到的输出 视图的定义 你可能没有之前没有接触过"视图"的概念,或是仅仅是从其他工具包例如ASP.NET MVC ...
- NancyFX 第四章 Nancy快速上手 (使用Nancy模板)
在我们进一步深入学习Nancy之前,我们先快速的了解下Visual Studio下的Nancy模板. 采用Nancy模板,创建一个Nancy项目就像我们创建MVC应用或winForm应用一样简单,只需 ...
- Python 3 中生成器函数yield表达式的使用
生成器函数或生成器方法中包含了一个yield表达式.调用生成器函数时,会返回一个迭代子,值从迭代子中每次提取一个(通过调用其__next__()方法).每次调用__next__()时,生成器函数的yi ...
- 【django之分页器】
一.什么是分页功能 二.Django的分页器(paginator) 语法: paginator = Paginator(book_list, 8) #8条一页print("count:&qu ...
- 笔记:Hibernate 查询缓存
Hibernate 的一级缓存和二级缓存都是对实体进行缓存,他不会缓存普通属性,如果想对普通熟悉进行缓存,可以考虑使用查询缓存. 对于查询缓存来说,他缓存的Key就是查询所用的 HQL 或者 SQL ...