IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 为什么在Java中重写equals()方法同时要重写hashcode()方法 -> 正文阅读

[Java知识库]为什么在Java中重写equals()方法同时要重写hashcode()方法

??要彻底了解透为什么重写equals()方法同时要重写hashcode()方法,我们不妨先来看看这样一个例子:

        String a=new String("123");
        String b=new String("123");
        System.out.println(a==b);    //false
        System.out.println(a.equals(b));     //true
        System.out.println(a.hashCode()==b.hashCode());    //true

??在以上例子中,我们创建了两个字符串对象,虽然两个字符串对象的内容是相同的,都是“123”,但显然这是两个不同的对象,符号“ = = == ==”比较的是对象的在内存中的物理地址,既然a、b是两个不同的对象,那么他们对象的物理地址肯定不同,所以表达式“a = = == ==b”结果是false。众所周知,equals()方法的作用本来和==相同,也是比较两者的物理地址,这一点可以在Object类中equals()方法的实现中可以证明:

  public boolean equals(Object obj) {
        return (this == obj);
   }

但是在String类中重写了equals()方法:

public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String aString = (String)anObject;
            if (coder() == aString.coder()) {
                //比较的是String对象的value属性,也就是字符串内容
                return isLatin1() ? StringLatin1.equals(value, aString.value)
                                  : StringUTF16.equals(value, aString.value);
            }
        }
        return false;
    }

于是String类的equals方法变成了比较两个字符串对象的字符串内容是否相等,所以表达式“a.equals(b)”结果是true,那么为什么表达式“a.hashCode()==b.hashCode()”的结果也是true呢,是因为hashCode()方法在String类中也进行了重写。
??我们可以比较一下hashCode()方法在Object类中的实现以及在String类重写之后的实现。

这是hashCode()在Object类中的实现:

@HotSpotIntrinsicCandidate
    public native int hashCode();

??从声明关键字native可以看出这是一个本地方法,具体是用更加底层的C语言实现的,大概阅读native方法的注释说明后可以了解到hashCode()方法返回的是一个数字,这个数字对于同一个对象来说具有唯一性,与这个对象的引用无关,只与这个对象的内存物理地址有关

我们再来看看hashCode()方法在String类中的实现:

//String: hashCode()
public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            hash = h = isLatin1() ? StringLatin1.hashCode(value)
                                  : StringUTF16.hashCode(value);
        }
        return h;
    }

//StringLatin1.hashCode(value)
 public static int hashCode(byte[] value) {
        int h = 0;
        for (byte v : value) {
            h = 31 * h + (v & 0xff);
        }
        return h;
    }

??从实现方式中我们也可以看出,hashCode()也和equals()方法从与对象物理内存地址相关变成了与对象字符串的内容相关。

??也就是说,如果通过equals()方法判断两个对象是否相等的结果要与两个对象hashCode()方法返回的整数进行比较得出的结果保持一致性,那么为什么要这样做呢?
??首先,我们要明白hashCode()方法的作用是确定对象在散列存储结构例如HashMap、HashSet中的存储地址(注:这个地址不是对象在内存中的真实存储地址,只是在数据结构中的逻辑地址)。
??此刻我们就能回答为什么重写equals()方法同时要重写hashcode()方法了:如果重写了equals()方法,没有重写hashCode()方法的话,如果a.equals(b),但a的hashCode与b的hashCode不相等,则当我们将a、b同时加入散列存储结构map、set时,就可能出现数据结构中存在两个值相等的对象的情况,从而导致混淆。
??所以我们在设计Java类对象要遵循以下原则:

  1. 如果两个对象通过equals()方法比较相等,那么这两个对象的hashCode一定相同。
  2. 如果两个对象hashCode相同,不能证明两个对象是同一个对象,只能证明两个对象在散列结构中存储在同一个地址(不同对象hashCode相同的情况称为hash冲突)。

最后我们来看看遵守以上原则的String类在散列存储结构中的存储情况:

        String a=new String("123");
        String b=new String("123");
        System.out.println(a==b);   //false
        System.out.println(a.equals(b));    //true
        System.out.println(a.hashCode()==b.hashCode());    //true

        Set<String>set=new HashSet<>();
        set.add(a);
        System.out.println(set.contains(b));   //true

??以上例子可以看出,虽然a、b不是同一个对象,但是由于表达式“a.equals(b)”结果是true,所以a的hashCode与b的hashCode相等,两者在set中存储地址相同,在set中加入a后,在set中查询b,返回结果是true。
??综上,重写equals()方法同时尽量也要重写hashcode()方法。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-07-23 10:35:34  更:2021-07-23 10:37:04 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/17 20:23:49-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码