你所忽略的,覆盖equals时需要注意的事项《effective java》

  我们都知道Object的equals的比较其实就是==的比较,其实是内存中的存放地址的比较。正常逻辑上:类的每个实例本质上都是唯一的。

  在工作中我们实际的业务逻辑往往有可能出现一些相对特殊的需求需要对equals方法进行重写,那么重写equals需要注意哪些规则或者通用的约定呢?

 

equals方法实现了等价关系(equivalence relation)

  • 自反性(reflexive)。对于任何非null的引用值xx.equals(x)必须返回true
  • 对称性(symmetric)。对于任何非null的引用值xy,当且仅当y.equals(x)返回true时,x.equals(y)必须返回true
  • 传递性(transitive)。对于任何非null的引用值xyz。如果x.equals(y)返回true,并且y.equals(z)也返回true,那么x.equals(z)也必须返回true
  • 一致性(consistent)。对于任何非null的引用值xy,只要equals的比较操作在对象中所用的信息没有被修改,多次调用x.equals(x)就会一致地返回true,或者一致的返回false
  • 对于任何非null的引用值xx.equals(null)必须返回false

第一点自反性不需要多说,基本上不可能会出现违背这条约定的情况当自己和自己比较的时候返回false。

第二点对称性,这种情况还是有可能会出现的。我们可以假设一个场景,这个场景是我们创建一个类并且里面只有一个String属性字段,这个类需要实现的是可以不区分字符串的大小写。

pubilc final class IgnoreCaseString {private final String s;public IgnoreCaseString(String s) {if (s == null)throw new NullPointerException();this.s = s;}@Overridepublic boolean equals(Object o) {if (o instanceof IgnoreCaseString)return s.equalsIgnoreCase(((IgnoreCaseString) o).s);if (o instanceof String)return s.equalsIgnoreCase((String) o);return false;}

  ...//更多代码(重写equals就需要重写hashCode) }

在这个类中,equals方法的意图非常好,它的企图是可以与普通的字符串对象进行互操作。但是这段代码无意中触犯了对称性这个约定,从new IgnoreCaseString(“Po”).equals("po")是为true的,但是反过来“po”.equals(new IgnoreCaseString("Po"))的结果是false。假如违反了这一情况而没有去更正,他会破坏已有的集合框架的一些方法,使其变的不在准确。

IgnoreCaseString ics = new IgnoreCaseString("Po");List<IgnoreCaseString> list = new ArrayList<IgnoreCaseString>();list.add(ics);System.out.println(list.contains("po"));List<String> list1 = new ArrayList<>();list1.add("po");System.out.println(list1.contains(ics));

结果是,此时list.contains(s)会返回什么结果呢?没人知道,在Sun的当前实现中,它碰巧返回false,但这只是这个特定实现得出的结果而已。在其他的实现中,它有可能返回true(如上面代码中的list1.contains(ics)),或者抛出一个运行时(runtime)异常。一旦违反了equals约定,当其他对象面对你的对象时,你完全不知道这些对象的行为会这么样。

第三点传递性,equals约定:如果一个对象等于第二个对象,并且第二个对象又等于第三个对象,则第一个对象一定等于第三个对象。无意识违反这一情况其实不难想象,考虑子类的情形,子类增加的信息会影响到equals的比较结果。

public class TwoDCoordinate {private final int x;private final int y;public TwoDCoordinate(int x, int y) {this.x = x;this.y = y;}@Overridepublic boolean equals(Object o) {if (!(o instanceof TwoDCoordinate))return false;TwoDCoordinate p = (TwoDCoordinate)o;return p.x == x && p.y == y;}
  ...//更多代码
(重写equals就需要重写hashCode)
} 
public class ThreeDCoordinate extends TwoDCoordinate{
  
private final int z;
  
public ThreeDCoordinate(int x, int y, int z) {
    
super(x, y); this.z=z;
  }

  @Override
  
public boolean equals(Object o) {
    
if (!(o instanceof TwoDCoordinate))
      
return false;
    
if (!(o instanceof ThreeDCoordinate))
      
return o.equals(this);
    
return super.equals(o) && this.z == ((ThreeDCoordinate) o).z;
  }
  
  ...//更多代码
(重写equals就需要重写hashCode)
}
ThreeDCoordinate t1 = new ThreeDCoordinate(1, 2, 3);TwoDCoordinate t2 = new TwoDCoordinate(1, 2);ThreeDCoordinate t3 = new ThreeDCoordinate(1, 2, 4);System.out.println(t1.equals(t2));System.out.println(t2.equals(t1));System.out.println(t2.equals(t3));System.out.println(t1.equals(t3));

结果是true  true   true   false,上述代码已经满足了自反性和对称性的约定,但是没有满足传递性,t1.equals(t2)为true,t2.equals(t3)为true,t1.equals(t3)却为false。

这种情况很多程序员会犯。

 想要避免这种情况,其实可以用getClass测试代替instanceof测试。如将TwoDCoordinate 的equals 方法改为

public boolean equals(Object o) {if (o == null || o.getClass() != this.getClass())return false;TwoDCoordinate p = (TwoDCoordinate)o;return p.x == x && p.y == y;}

这种替代方式其实不会太糟糕,但是结果却不会太理想,暂时没有想到令人满意的办法实现既可以扩展又不可实例化的类,但是可以考虑复合优先于继承。

第四点一致性,equals约定的第四个要求是,如果两个对象相等,它们就必须始终保持相等,除非它们中有一个对象(或者两个都)被修改了。换句话说,可变对象在不同的时候可以与不同的对象相等,而不可变对象则不会这样。当你在写一个类的时候,应该仔细考虑她是否应该是不可变的。如果认为它应该是不可变的,就必须保证equals方法满足这样的限制条件:相等的对象永远相等,不相等的对象永远不相等。

 

转载于:https://www.cnblogs.com/saoyou/p/10318517.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/412343.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

bootstrap 一排5个_BootStrap从基础到项目实战_第1季_03章_02_CSS样式栅格系统实例

目标目标一、理解什么是栅格布局目标二、掌握栅格布局具体应用目标三、掌握BootStrap通用CSS样式(排版、代码、代码、表单、按钮、图片、辅助类、响应式工具)内容一、BootStrap全局CSS之 - 栅格系统实例1.1 栅格系统实例实战前的理论准备通过下面的截图可以比较清楚的来查看Boo…

光耦驱动单向可控硅_光耦是什麽?

光耦是一种广泛用于电子产品中的元器件&#xff0c;亦称作光电耦合器或是光电隔离器&#xff0c;光耦的动作顺序为一个电→光→电的过程&#xff0c;光耦元件于输入端由电讯号转为光讯号&#xff0c;输出端则吸收光讯号后转换为电流/电压&#xff1b;在实体电路上光耦确实的隔离…

单体预聚合的目的是什么_线型低密度聚乙烯的单体单元比例到底是多少?

我国现行法定归类依据关于线型低密度聚乙烯(LLDPE)单体单元比例的规定主要可见于三处&#xff1a;第三十九章总注释&#xff1a;“值得注意的是&#xff0c;商品聚合物有时含有比其缩写名称所述的单体单元要多〔例如&#xff0c;线性低密度聚乙烯(LLDPE)基本上是乙烯聚合物&…

银行系统日终结算要多久_美股顽强翻红!两连跌终结,联储降息预期已超九成!制造业疲软消费者信心坚挺,三大股指又假摔?...

美国股市昨日先抑后扬终结两连跌&#xff0c;开启反弹&#xff0c;道指、标普、纳指纷纷翻红。10月3日晚&#xff0c;美东时间周四&#xff0c;美股集体低开&#xff0c;盘初受宏观经济数据不及预期影响&#xff0c;三大指数大幅跳水跌逾1%&#xff0c;道指跌超300点。此后美股…

mysql优化三

相对高并发一样,速度都是优化出来的,在高并发处理的时候,通常采用的是redis缓存,全文搜索引擎,数据库本身优化,sql优化,磁盘优化 看如下图: 所以可以得出的思想就是: 这个优化法则归纳为5个层次&#xff1a;1、 减少数据访问&#xff08;减少磁盘访问&#xff09;2、 返回更少数…

smartdeblur有手机版吗_《GTA5》高仿手机版问世,更新高清城市地图后你会喜欢吗?...

现在GTA5手游是传的最热火的一款手游了&#xff0c;但R星并没有把这款游戏排在日程上面&#xff0c;我觉得2K的游戏制作速度确实太慢&#xff0c;以至于R星都要亲自去催一下&#xff0c;而且现在是手游的天下&#xff0c;更多的游戏群体都开始在手游端聚集&#xff0c;在未来的…

Asp.Net集成支付宝当面付接口报ISV权限不足

在使用C#开发支付宝当面付接口时&#xff0c;下载了[官网的Demo] 点此链接进入下载&#xff1a; https://doc.open.alipay.com/doc2/detail.htm?spma219a.7629140.0.0.yNFbBr&treeId193&articleId105201&docType1 使用公司的支付宝商家账号替换好参数后&#xff…

ad采样做按键开关_磐石按键测试机解决各种按键测试问题

随着人民生活水平不断的提高&#xff0c;在使用各类产品的过程中&#xff0c;对手指碰触到的按键要求舒适性越来越高&#xff0c;也就是对产品用户体验的享受度越来越高&#xff0c;对手碰触到的各类按键的要求灵敏度、可靠度、舒适性就非常高&#xff0c;所以现在很多产品在出…

巨潮网怎么下载年报_上市公司年报(或财务报表)在哪里下载?

会计专业;财务分析;上市公司;技巧 首先,上市公司财务报表通常指的是三大财务报表:资产负债表 现金流量表 利润表,Excel格式的;当然也有人需要的是PDF格式的完整年度报告,看您具体需要的事哪一种,依照情况选择吧。Excel>> PDF>> 2. 在查询获取上常用的是巨…

redis将散裂中某个值自增_0基础掌握Django框架(49)Redis

为了更好的学习效果&#xff0c;请搭配视频教程一起学习&#xff1a;Django零基础到项目实战 - 网易云课堂​study.163.comredis教程&#xff1a;概述redis是一种nosql数据库,他的数据是保存在内存中&#xff0c;同时redis可以定时把内存数据同步到磁盘&#xff0c;即可以将数据…

Asp.Net微信发布菜单,出现“invalid sub button url domain hint”错误

在微信后台建立好微信菜单后&#xff0c;调用发布接口进行发布操作时&#xff0c;出现了下面的问题&#xff1a; invalid sub button url domain hint [V85WIa0180vr23] 解决办法&#xff1a; 进入微信公众平台&#xff0c;选择菜单“公众号设置”-》“功能设置”-》“JS接口…

[vue] vue项目有做过单元测试吗?

[vue] vue项目有做过单元测试吗&#xff1f;# 个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关前端面试题

bootstrap综合大作业_齐齐哈尔市克东县城市管理综合执法局昼夜奋战清冰雪,全力以赴保畅通...

近日&#xff0c;克东县再次迎来降雪&#xff0c;此次降雪时间长、密度大&#xff0c;为保证城区内交通顺畅及人员车辆出行安全&#xff0c;克东县城市管理综合执法局组织城管大队和环卫站科学统筹、迅速行动&#xff0c;全力以赴投入到清冰雪工作中。11月17日晚十点&#xff0…

洛谷4951 地震 bzoj1816扑克牌 洛谷3199最小圈 / 01分数规划

洛谷4951 地震 1 #include<iostream>2 #include<cstdio>3 #include<algorithm>4 #define go(i,a,b) for(register int ia;i<b;i)5 #define ll long long6 #define db long double7 #define M 100018 #define N 4019 #define inf 1e15 10 #define eps 1e-…

jsx怎么往js里传参数_Angular、React 当前,Vue.js 优劣几何?

在过去一年里&#xff0c;前端开发发展迅速&#xff0c;前端工程师的薪资亦是水涨船高。2019 更是热度不减&#xff0c;而作为近年来尤为热门的前端框架&#xff0c;Vue.js 自是积累了大量关注。那么&#xff0c;Vue.js 是适合你的框架吗&#xff1f;以下为译文&#xff1a;对于…

Concurrent HTTP connections in Node.js

原文&#xff1a; https://fullstack-developer.academy/concurrent-http-connections-in-node-js/ ------------------------------------------------------------------------------------------ Browsers, as well as Node.js, have limitations on concurrent HTTP connec…

形状相似的物品_空运一般货物及危险品和特殊物品对包装的要求和规定!

一.空运包装的基本作用1.包装的基本作用有三种&#xff1a;保护、保存和介绍。包装应在贮存期间和从制造厂运至消费中心期间&#xff0c;起到保护和保存内部货物的作用。保护货物不仅包括防止丢失、损坏和被盗&#xff0c;还包括根据货物的性质&#xff0c;防止货物受潮、失火、…

coreldraw x4怎么会蓝屏_CorelDRAW广告条幅批量制作插件

由VBA探秘站长个人开发的一款条幅插件&#xff0c;用于广告行业快速制作条幅的好帮手。 所有用户可以在这个开源的版本基础上二次开发完善。界面截图软件架构基于VBA语言开发&#xff0c;插件形式为GMS。安装教程如果是非开发者用户&#xff0c;想直接使用插件&#xff0c;请直…

Python中数字之间的进制转换

https://www.cnblogs.com/Kingfan1993/p/9795541.html 在python中可以通过内置方法进行相应的进制转换&#xff0c;但需记得转化成非十进制时&#xff0c;都会将数字转化成字符串 转化成二进制 a 10 #声明数字&#xff0c;默认十进制 b bin(a) print(b , type(b)) 运行结果&…

私有5g网络_Verizon与诺基亚合作部署私有5G网络

点击上方“IEEE电气电子工程师”即可订阅公众号。网罗全球科技前沿动态&#xff0c;为科研创业打开脑洞。SOPA Images via Getty ImagesVerizon宣布&#xff0c;Verizon将与诺基亚合作&#xff0c;创建私人5G设备&#xff0c;在大型“制造、分销和物流设施”中取代WiFi。这个想…