建议47: 在equals中使用getClass进行类型判断

本节我们继续讨论覆写equals的问题。这次我们编写一个员工Employee类继承Person类,这很正常,员工也是人嘛,而且在JEE中JavaBean有继承关系也很常见,代码如下:

 1 public class Client {
 2     public static void main(String[] args) {
 3          Employee e1 = new Employee("张三",100);
 4          Employee e2 = new Employee("张三",1001);
 5          Person p1 = new Person("张三");
 6          System.out.println(p1.equals(e1));
 7          System.out.println(p1.equals(e2));
 8          System.out.println(e1.equals(e2));
 9     }
10 }
11
12 class Person{
13     private String name;
14
15     public Person(String _name){
16        name = _name;
17     }
18
19     @Override
20     public boolean equals(Object obj) {
21          if(obj instanceof Person){
22            Person p = (Person) obj;
23            return name.equalsIgnoreCase(p.getName().trim());
24          }
25          return false;
26     }
27
28     public String getName() {
29         return name;
30     }
31
32     public void setName(String name) {
33         this.name = name;
34     }
35 }
36
37 class Employee extends Person{
38     private int id;
39     /*id的getter/setter方法省略*/
40     public Employee(String _name,int _id) {
41          super(_name);
42          id = _id;
43     }
44
45     public int getId() {
46         return id;
47     }
48
49     public void setId(int id) {
50         this.id = id;
51     }
52
53     @Override
54     public boolean equals(Object obj) {
55          if(obj instanceof Employee){
56            Employee e = (Employee) obj;
57            return super.equals(obj)&& e.getId() == id;
58          }
59          return false;
60     }
61 } 

输出结果:

true
true
false

很不给力嘛,p1竟然等于e1,也等于e2,为什么不是同一个类的两个实例竟然也会相等呢?这很简单,因为p1.equals(e1) 是调用父类Person的equals方法进行判断的,它使用instanceof关键字检查e1是否是Person的实例,由于两者存在继承关系,那结果当然是true了,相等也就没有任何问题了,但是反过来就不成立了,e1或e2可不等于p1,这也是违反对称性原则的一个典型案例。

更玄的是p1与e1、e2相等,但e1竟然与e2不相等,似乎一个简单的等号传递都不能实现。这才是我们要分析的真正重点:e1.equals(e2)调用的是子类Employee的equals方法,不仅仅要判断姓名相同,还要判断工号是否相同,两者工号是不同的,不相等也是自然的了。等式不传递是因为违反了equals的传递性原则,传递性原则是指对于实例对象x、y、z来说,如果x.equals(y)返回true,y.equals(z)返回true,那么x.equals(z)也应该返回true。

这种情况发生的关键是父类使用了instanceof关键字,它是用来判断是否是一个类的实例对象的,这很容易让子类“钻空子”。想要解决也很简单,使用getClass来代替instanceof进行类型判断,Person类的equals方法修改后如下所示:

 1 public boolean equals(Object obj) {
 2      if(obj!=null && obj.getClass() == this.getClass()){
 3         Person p = (Person) obj;
 4         if(p.getName()==null || name==null){
 5             return false;
 6         }else{
 7             return name.equalsIgnoreCase(p.getName());
 8         }
 9      }
10      return false;
11 } 

当然,考虑到Employee也有可能被继承,也需要把它的instanceof修改为getClass。总之,在覆写equals时建议使用getClass进行类型判断,而不要使用instanceof。

[改善Java代码]在equals中使用getClass进行类型判断相关推荐

  1. [改善Java代码]减少HashMap中元素的数量

    在系统开发中我们经常会使用HashMap作为数据集容器,或者是用缓冲池来处理,一般很稳定,但偶尔也会出现内存溢出的问题(OutOfMemory错误),而且这经常是与HashMap有关的.而且这经常是与 ...

  2. [改善Java代码]在接口中不要存在实现代码

    第3章  类.对象及方法 书读得多而不思考,你会觉得自己知道的很多. 书读得多而思考,你会觉得自己不懂的越来越多. -伏尔泰 在面向对象编程(Object-Oriented Programming,O ...

  3. java 代码解析工具_改善 Java 代码质量的工具与方法

    原标题:改善 Java 代码质量的工具与方法 我们可能见过上面的有关代码质量的图片,究竟如何衡量一段代码好坏? 代码质量是什么?为什么它很重要? 作家通过他的著作来讲述了一个清晰的.令人信服的故事.他 ...

  4. 教你如何使用Java代码从网页中爬取数据到数据库中——网络爬虫精华篇

    文章目录 1:网络爬虫介绍 2:HttpClients类介绍 2.1 HttpGet参数问题 2.2 HttpPost参数问题 2.3 连接池技术问题 3:Jsoup介绍 4:动手实践如何抓取网页上数 ...

  5. 改善Java代码有哪些方法?

    前言 Java是一门优秀的面向对象的编程语言,针对遇到同样的一个问题会有很多中解法哪种实现方法是最好的呢,还需要不断的探究JDK的底层原理.我会例出Java改善的建议哦,希望大家可以在平时开发工作去使 ...

  6. java代码在jsp中怎么写_在jsp中写java代码

    该服务器上的所有的访问者的所有 jsp 页面 D.该服务器上的所有的访问者的所有 jsp 页面和 Java 程序 6.在 JSP 中调用 JavaBean 时不会用到的标记是( )...... jav ...

  7. Java代码---求数组中的平均值

    Java代码-求数组中的平均值 /*** 求数组中的平均值*/ class Demo5 {public static void main(String[] args) {int[] array = { ...

  8. C#保留2位小数几种场景总结 游标遍历所有数据库循环执行修改数据库的sql命令 原生js轮盘抽奖实例分析(幸运大转盘抽奖) javascript中的typeof和类型判断...

    C#保留2位小数几种场景总结 场景1: C#保留2位小数,.ToString("f2")确实可以,但是如果这个数字本来就小数点后面三位比如1.253,那么转化之后就会变成1.25. ...

  9. [改善Java代码]覆写equals方法必须覆写hashCode方法

    覆写equals方法必须覆写hashCode方法,这条规则基本上每个Javaer都知道,这也是JDK API上反复说明的,不过为什么要这样做呢?这两个方法之间有什么关系呢?本建议就来解释该问题,我们先 ...

  10. [改善Java代码]避开基本类型数组转换列表陷阱

    开发中经常用到Arrays和Collections这两个工具类. 在数组和列表之间进行切换.非常方便.但是也会遇到一些问题. 看代码: import java.util.Arrays; import ...

最新文章

  1. C++ 虚函数与存虚函数
  2. MacOS无法登录App Store修复
  3. python数独代码_python 实现计算数独
  4. 地震射线追踪与有限差分正演模拟小软件
  5. Ajax Control Toolkit--Slider:有朝一日倒过来
  6. 230.二叉搜索树中第K小的元素
  7. android 修复工具下载,安卓数据恢复软件(FonePaw for Android)
  8. 这么多技术我该怎么学 杨中科
  9. 微信小程序,电子商城中快速实现收货地址(包含前端和后台实现)
  10. 基于SSM架构的网上书城系统
  11. Facebook IPO更改投行佣金标准 比例或降至1%
  12. Paper之ICASSPIEEEAUDIOSPE:2018~2019年ICASSP国际声学、语音和信号处理会议IEEE-ACM T AUDIO SPE音频、语音和语言处理期刊最佳论文简介及其解读
  13. ubuntu(服务端)+windows(客户端)搭建iscsi
  14. dubbo源码分析总结
  15. “掌商工程”让海派盆景与白领互添绿意
  16. 汽车多重定位,实时定位追踪,远程查看汽车运行轨迹
  17. webview的java与js互操作
  18. Hackintosh相关资源站
  19. 电脑启动项和系统引导项设置
  20. 2018年广东工业大学文远知行杯新生程序设计竞赛 1007 活在无尽梦境的后续 β

热门文章

  1. 安装ECShop报 Non-static method cls_image::gd_version() should not be called statically 解决方案
  2. GitHub 学习和使用
  3. HTML(三)选择器--复杂选择器
  4. CSS-Box模型--理解与整理
  5. AlwaysOn业务IP和高可用IP分开使用(四)
  6. ios 图片合成 处理合成模糊 水印 模板图片合成
  7. pip install 出现报asciii码错误的解决
  8. 【转】Unix的文件系统的内部结构,主要是超级块、inode相关知识
  9. rpm软件管理程序,yum仓库的作用
  10. Learn UML with JUDE(中文版)