• 猿创征文|对象比较“==”与“hashCode()”的孽缘(java 小虚竹)


    ❤️作者主页:小虚竹

    ❤️作者简介:大家好,我是小虚竹。Java领域优质创作者🏆,CSDN博客专家🏆,华为云享专家🏆,掘金年度人气作者🏆,阿里云专家博主🏆

    ❤️技术活,该赏

    ❤️点赞 👍 收藏 ⭐再看,养成习惯

    PC端左侧加我微信,进社群,有送书等更多活动!

    问题

    有个粉丝问虚竹哥:为什么内存地址一样,但比较用“==”时,结果是false;
    比较用equals()时,得到的结果是true。
    在这里插入图片描述

    分析

    虚竹哥刚开始也是一脸懵,使用clone方法 克隆出来的对象是新对象,(深入解析题目:【第33题】JAVA高级技术-对象克隆2(浅克隆)
    内存地址怎么可能会一样?
    但是粉丝就是截图出来了,有图有真相是吧
    难道是我记错了?
    我不信!
    写个代码验证下:
    Address类

    package com.xiaoxuzhu;
    
    /**
     * Description: 
     *
     * @author zenghw
     * @version 1.0
     *
     * 
     * 修改记录:
     * 修改后版本	        修改人		修改日期			修改内容
     * 2022/8/23.1	    zenghw		2022/8/23		    Create
     * 
    * @date 2022/8/23 */
    public class Address { private String state; // 表示员工所在的国家 private String province;// 表示员工所在的省 private String city; // 表示员工所在的市 public Address(String state, String province, String city) {// 利用构造方法进行初始化 this.state = state; this.province = province; this.city = city; } public String getState() { return state; } public void setState(String state) { this.state = state; } public String getProvince() { return province; } public void setProvince(String province) { this.province = province; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } @Override public String toString() {// 重写toString()方法 StringBuilder sb = new StringBuilder(); sb.append("国家:" + state + ", "); sb.append("省:" + province + ", "); sb.append("市:" + city); return sb.toString(); } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    Employee类:

    package com.xiaoxuzhu;
    
    /**
     * Description: 
     *
     * @author zenghw
     * @version 1.0
     *
     * 
     * 修改记录:
     * 修改后版本	        修改人		修改日期			修改内容
     * 2022/8/23.1	    zenghw		2022/8/23		    Create
     * 
    * @date 2022/8/23 */
    public class Employee implements Cloneable { private String name; // 表示员工的姓名 private int age; // 表示员工的年龄 private Address address;// 表示员工的地址 public Employee(String name, int age, Address address) {// 利用构造方法进行初始化 this.name = name; this.age = age; this.address = address; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } @Override public Employee clone() {// 实现浅克隆 Employee employee = null; try { employee = (Employee) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return employee; } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    再写个测试类:

    package com.xiaoxuzhu;
    
    /**
     * Description: 
     *
     * @author zenghw
     * @version 1.0
     *
     * 
     * 修改记录:
     * 修改后版本	        修改人		修改日期			修改内容
     * 2022/8/23.1	    zenghw		2022/8/23		    Create
     * 
    * @date 2022/8/23 */
    public class Test { public static void main(String[] args) { Address address = new Address("中国", "福建", "厦门");// 创建address对象 Employee employee1 = new Employee("小虚竹", 30, address);// 创建employee1对象 Employee employee2 = employee1.clone(); System.out.println(employee1); System.out.println(employee2); System.out.println(employee1 == employee2); } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    在这里插入图片描述
    clone克隆后的对象,内存地址是不一样的。虚竹哥拍了拍胸膛,安心了。
    但为什么粉丝得到了内存地址一样的对象呢?
    经常虚竹哥跟粉丝的沟通,终于找到问题了
    在这里插入图片描述
    问题出在重写了equals方法,也重写了hashCode方法。
    在打印对象时,发生了什么?可以来分析下

    System.out.println(employee1);

    在这里插入图片描述
    首先是调用PrintStream.println 方法,方法里对要打印的对象进行转化成字符串。
    在这里插入图片描述
    String.valueOf 方法对入参对象进行判空处理,如果为null时,返回字符串“null”。如果不是null,则调用对象的toString() 方法。
    一开始对Employee类 没有重写toString() 方法。 所以这里会进入Object对象toString() 方法。
    在这里插入图片描述

    打印的是employee1对象所继承的Object类中的hashCode方法返回的值。
    在这里插入图片描述
    但我们发现这个对象已经是native了,至于Object 的hashCode方法是如何取值的,大家可自行去看下源码,如何看源码传送门

    可知:不同的对象产生的hashCode是不同的;默认情况下,对象的hashCode是通过将该对象的内部地址转换成一个整数来实现的。

    好了,分析了这么多,回到粉丝的问题上来:
    在这里插入图片描述
    问题出在重写了equals方法,也重写了hashCode方法。
    因为粉丝把hashCode方法重写了,导致得到的hashCode值并不代表着内存地址了。

    System.out.println(employee1 == employee2);
    这里是内存地址的比较

    才会让人有一种错觉!内存地址(输出)明明一样,用比较“==”得到了false。

    四、推荐专栏

    《JAVA从零到壹》

    《JAVA筑基100例》

    我是虚竹哥,我们下期见~~~

  • 相关阅读:
    一键到位「GitHub 热点速览 v.22.32」
    VS报错 The build tools for v141 (Platform Toolset = ‘v141‘) cannot be found.
    Lambda初次使用很慢?从JIT到类加载再到实现原理
    Java基础—重新抛出异常
    快速上手若依代码生成器(2022)
    伦敦银走势图分析的新方法
    Windows PowerShell 使用
    潘多拉 (Pandora),一个让你呼吸顺畅的 ChatGPT
    SpringBoot 框架笔记
    pnpm入门教程
  • 原文地址:https://blog.csdn.net/shi_hong_fei_hei/article/details/126493372