一、重写equals方法

【Java比较学习】重写equals方法的安全写法

1、重写equals方法的两种方式

这里提供两个比较常见的equals重写方法:
● 用instanceof实现重写equals方法
● 用getClass实现重写equals方法

先说结论,getClass()比instanceof更安全。接下来就是我们自己要来实现equals方法了。

2、场景描述

假设有此场景:
在已经创建好的长方形类中重写Object类中的equals方法为当长方形的长和宽相等时,返回TRUE,同时重写hashCode方法,重写toString方法为显示长方形的长宽信息。并测试类。

package com.test10_04;import java.util.Objects;class Rectangle {private double length;private double wide;public Rectangle() {//空实现}public Rectangle(double length, double wide) {setLength(length);setWide(wide);}public double getLength() {return length;}public void setLength(double length) {assert length > 0.0 : "您的输入有误,长方形的长不能小于0";this.length = length;}public double getWide() {return wide;}public void setWide(double wide) {assert wide > 0.0 : "您的输入有误,长方形的宽不能小于0";this.wide = wide;}public double area() {return this.length * this.wide;}public double circumference() {return 2 * (this.wide + this.length);}public boolean equals(Object obj) {if (this == obj) { //判断一下如果是同一个对象直接返回true,提高效率return true;}if (obj == null || obj.getClass() != this.getClass()) { //如果传进来的对象为null或者二者为不同类,直接返回falsereturn false;}//也可以以下方法:
//        if (obj == null || !(obj instanceof Rectangle)) { //如果传进来的对象为null或者二者为不同类,直接返回false
//            return false;
//        }Rectangle rectangle = (Rectangle) obj; //向下转型//比较长宽是否相等,注意:浮点数的比较不能简单地用==,会有精度的误差,用Math.abs或者Double.comparereturn Double.compare(rectangle.length, length) == 0 && Double.compare(rectangle.wide, wide) == 0;}public int hashCode() { //重写equals的同时也要重写hashCode,因为同一对象的hashCode永远相等return Objects.hash(length, wide); //调用Objects类,这是Object类的子类}public String toString() {return "Rectangle{" + "length=" + length + ", wide=" + wide + '}';}
}public class TestDemo {public static void main(String[] args) {Rectangle rectangle1 = new Rectangle(3.0, 2.0);Rectangle rectangle2 = new Rectangle(3.0, 2.0);System.out.println(rectangle1.equals(rectangle2));System.out.println("rectangle1哈希码:" + rectangle1.hashCode() +"\nrectangle2哈希码:" + rectangle2.hashCode());System.out.println("toString打印信息:" + rectangle1.toString());}
}

3、getClass和instanceof优缺点

具体实现思路在代码中讲的很清楚了,我们这里重点分析一下getClass和instanceof两种实现方法的优缺点:

将代码逻辑简化一下:
我们就重点看这段简单的代码

//getClass()版本
public class Student {private String name;public void setName(String name) {this.name = name;}@Overridepublic boolean equals(Object object){if (object == this)return true;// 使用getClass()判断对象是否属于该类if (object == null || object.getClass() != getClass())return false;Student student = (Student)object;return name != null && name.equals(student.name);
}

事实上两种方案都是有效的,区别就是getClass()限制了对象只能是同一个类,而instanceof却允许对象是同一个类或其子类,这样equals方法就变成了父类与子类也可进行equals操作了,这时候如果子类重定义了equals方法,那么就可能变成父类对象equlas子类对象为true,但是子类对象equlas父类对象就为false了,如下所示:

class GoodStudent extends Student {@Overridepublic boolean equals(Object object) {return false;}public static void main(String[] args) {GoodStudent son = new GoodStudent();Student father = new Student();son.setName("test");father.setName("test");// 当使用instance of时System.out.println(son.equals(father)); // 这里为falseSystem.out.println(father.equals(son)); // 这里为true// 当使用getClass()时System.out.println(son.equals(father)); // 这里为falseSystem.out.println(father.equals(son)); // 这里为false  }
}

注意看这里用的是getClass()

返回值两个都是false,符合我们的预期,(连类都不一样那肯定得为false啊)

而换成instanceof试试看咯:

运行结果:一个为true一个为false,很明显出现问题了。

这里的原因如下:
instanceof的语法是这样的:
当一个对象为一个类的实例时,结果才为true。但它还有一个特点就是,如果当这个对象是其子类的实例时,结果也会为true。这便导致了上述的bug。也就是说当比较的两个对象,他们的类是父子关系时,instanceof可能会出现问题。需要深究的小伙伴可以自己去了解一哈,所以在这里建议在实现重写equals方法时,尽量使用getClass来实现。
在重写equals方法的同时需要重写hashCode方法,具体原因可能后续会讲到~~

4、instanceof和getClass总结

区别就是getClass()限制了对象只能是同一个类,而instanceof却允许对象是同一个类或其子类,

5、instanceof实战

public class GenericTest01 {public static void main(String[] args) {// 使用JDK5之后的泛型机制// 使用泛型List<Animal>之后,表示List集合中只允许存储Animal类型的数据。// 用泛型来指定集合中存储的数据类型。List<Animal> myList = new ArrayList<Animal>();// 指定List集合中只能存储Animal,那么存储String就编译报错了。// 这样用了泛型之后,集合中元素的数据类型更加统一了。//myList.add("abc");Cat c = new Cat();Bird b = new Bird();myList.add(c);myList.add(b);// 获取迭代器// 这个表示迭代器迭代的是Animal类型。Iterator<Animal> it = myList.iterator();while(it.hasNext()){// 使用泛型之后,每一次迭代返回的数据都是Animal类型。//Animal a = it.next();// 这里不需要进行强制类型转换了。直接调用。//a.move();// 调用子类型特有的方法还是需要向下转换的!Animal a = it.next();if(a instanceof Cat) {Cat x = (Cat)a;x.catchMouse();}if(a instanceof Bird) {Bird y = (Bird)a;y.fly();}}}
}class Animal {// 父类自带方法public void move(){System.out.println("动物在移动!");}
}class Cat extends Animal {// 特有方法public void catchMouse(){System.out.println("猫抓老鼠!");}
}class Bird extends Animal {// 特有方法public void fly(){System.out.println("鸟儿在飞翔!");}
}

【Java基础】重写equals方法详讲相关推荐

  1. Java中重写equals()方法时注意点

    Java中重写equals()方法时注意点 一直说,重写一个对象的equals()方法时我们必须重写HashCode()方法,但是如果我们不重写呢?会有什么影响呢? 首先看一下,什么情况下我们需要重写 ...

  2. java 对象重写equals方法_Java如何重写object类的equals方法详解

    1.Object类的equals()方法: 比较两个对象是否是同一个对象,equals() 方法比较两个对象,是判断两个对象引用指向的是同一个对象,即比较 2 个对象的内存地址是否相等.是则返回tru ...

  3. JAVA中重写equals()方法的同时要重写hashcode()方法

    object对象中的 public boolean equals(Object obj),对于任何非空引用值 x 和 y,当且仅当 x 和 y 引用同一个对象时,此方法才返回 true:注意:当此方法 ...

  4. JAVA基础--toString, equals方法

    ==比较的是地址 equals比较的是内容. 所以要重写object的equals方法. public class TestEquals {public static void main(String ...

  5. Java基础——重写toString()方法

    1.Object()类的toString() Java默认的toString方法来自Object类 在Java中每个类都直接或者间接继承Object类,toString()方法同样是来自于Object ...

  6. Java基础之equals方法和= =的区别

    ==操作符专门用来比较两个变量的值是否相等,也就是用于比较变量所对应的内存中所存储的数值是否相同,要比较两个基本类型的数据或两个引用变量是否相等,只能用==操作符. 如果一个变量指向的数据是对象类型的 ...

  7. java equals重写原则_java中为何重写equals时必须重写hashCode方法详解

    前言 大家都知道,equals和hashcode是java.lang.Object类的两个重要的方法,在实际应用中常常需要重写这两个方法,但至于为什么重写这两个方法很多人都搞不明白. 在上一篇博文Ja ...

  8. Java基础321 - 如何重写equals方法

    目录 如何重写equals方法 Pig实体类 测试方法 如何重写equals方法 应用实例: 判断两个Pig对象的内容是否相等,如果两个Pig对象的各个属性都一样,则返回true,反之false. 1 ...

  9. java equals方法详解

    序言:准备总结一些java基础的知识方便以后查阅,从equals入手 目录: 等于(==)详解 equals方法详解 一.等于(==)详解 先明确一点:"==" 其实是存储地址的比 ...

最新文章

  1. 董明珠:别嫌工资少,满足这些条件!多高都给你
  2. Docker报错 WARNING: IPv4 forwarding is disabled. Networking will not work.
  3. api代理提取_了解提取API
  4. 第一百二十四期:2019年臭名昭著的勒索软件,网络钓鱼和僵尸网络
  5. win7 64位运行不了服务器,G6-e标准包可以装在win7 64位系统上吗?现在提示不能登陆到服务器...
  6. DataTable随机复制一行给新的DataTable
  7. pointnet2(pointnet++)源码复现
  8. ddmmyy日期格式是多少_DDMMYY什么意思?
  9. 将SPS中被FrontPage修改过的页面重置为Ghost Page
  10. scala 基础类库 —— 文件操作
  11. Linux开发_printf打印无消息或末尾带“#“or“%“
  12. vba宏语言_Excel VBA(1) – VBA 简介及录制宏
  13. 西安80北京54,2000和WGS84互转C#程序
  14. [转]欧洲航天局计划于2018年登月寻水
  15. ndk命令行编译so库
  16. 类型数组HTML5 中的新数组
  17. 从ADK的WinPE自己手动构建自己的PE
  18. C#事务处理(三)之Transactions事务
  19. 【云代码】ip代理手机路由器对游戏行业的作用
  20. 用户使用手册与测试报告(团队作业)

热门文章

  1. 手把手教你如何利用Meterpreter渗透Windows系统
  2. Navicat连接腾讯云服务器的MySQL
  3. 做了三年数据分析,给你的几点建议
  4. 手眼标定_全面细致的推导过程
  5. 开源版本_开源绘画应用 Pinta 在 5 年后迎来新版本 | Linux 中国
  6. 基于(ztmap)BIM的数字孪生建造智慧机房管理后台展示系统
  7. 网易大数据面试题试解
  8. SAP UI5 应用开发教程之八十五 - 如何用 OPA5 编写测试用例来测试用户输入文本的功能试读版
  9. 鱼鹰软件签约新三板挂牌企业风盛股份
  10. unigui unidbgrid导出Excel