我的编程空间,编程开发者的网络收藏夹
学习永远不晚

详解Java中的hashcode

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

详解Java中的hashcode

一、什么是hash

Hash,一般翻译做散列、杂凑,或音译为哈希,是把任意长度的输入(又叫做预映射pre-image)通过散列算法变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,所以不可能从散列值来确定唯一的输入值。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。

这个说的有点官方,你就可以把它简单的理解为一个key,就像是map的key值一样,是不可重复的。

二、hash有什么用?,在什么地方用到?

1.在散列表

2.map集合

此处只是做了一个简单的介绍,其实远远没有那么简单,如算法里面的散列表,散列函数,以及map的一个不可重复到底是怎么样去判断的,以及hash冲突的问题,都与hash值离不开关系。

三、java中String类的hashcode方法


public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

可以看到,String类的hashcode方法是通过,char类型的方式进行一个相加,因为String类的底层就是通过char数组来实现的。

如:String str="ab"; 其实就是一个char数组 char[] str={'a','b'};

如:字符串 String star=“ab”;那么他对应的hash值就是:3105

怎么算出来的呢?

val[0]='a' ; val[1]='b'

a对应的Ascall码值为:97
b对的Ascall码值为:98
那么经过如下代码的循环相加


 for (int i = 0; i < value.length; i++) {
            h = 31 * h + val[i];
        }

得出:97*31+98=3105;

我们再看: int h = hash;这一个代码,为什么有时候调用hashcode方法返回的hash值是负数呢?

因为如果这个字符串很长?那么h的值就会超过int类型的最大值,有没有想过,如果一个int类型的最大值,超过他的范围之后会怎么样呢?

我们先来看这样一个简单的代码:


 int count=0;
    while (true){
   if (count++<10){
            System.out.println("hello world");
          
        }
    }

大家认为hello world会输出多少次呢?
正常情况来说count小于10就不会输出了对么?
但是其实并不是这样的,很明确的告诉大家,这是一个死循环。

因为count一直加,最开始if成立,到后面的if不成立,再到后面if会再次成立,为什么会成立呢?因为count变为了负数。

???? 为什么?因为count一直无限制的加,由于是线性增长,计算速度是非常快的,所以,要不了多久,就会超出int类型的最大值。控制输出的count变为了负数,所以呢此时的if条件又成立了。

在这里插入图片描述

首先我们来看下int的范围 :int 为4个字节,一个字节为8位,一个int值是需要的存储空间是32位,但是呢?这是一个有符号位的int,需要一个符号位来表示正数和负数,
int值的范围就是:-2^31 ~ 2^31 也就是:-2147483648 到2147483647

我们来看下int最大值对应的二进制位是对少?

在这里插入图片描述

全是1? 2147483647最大值不是一个正数么?难道第一位难道不是应该用0表示么?

此时这个0他是省略掉了没写的,由于二进制系统是通过补码来保存数据的。第一位是符号位,0为正,1为负,当正的除了符号位全为1,再加1就进位了,符号位就会变成1,是负数,其他为0。
所以说当int的最大值加一个1,就变为了,最小值

来!口说无凭,没有说服力,我们直接来看代码:

在这里插入图片描述

那么我们在反过来想,最小值减1呢?那是不是就是对对应的是我们int类型的最大值了呀?

认真仔细的看完这个,你就知道为什么hashcode方法调用的时候有时候是正数,有时候是负数了吧?所以说底层还是很有意思的,比如往后做大数据开发,那么肯定是需要深入理解这些数据类型的范围,以及他的一个变化规则,否则有时候不知不觉的就犯错了,你还不知道错误在那儿?严重的话就是会损失精度,导致结果和你预期的结果相差甚远。就因为加了个1,就导致结果和预期结果相差十万八千里。

这是String类的hashcode方法的一个具体实现过程。

四、两个对象的 hashCode()相同,则 equals()也一定为 true,对吗?

首先呢?这个肯定是不对的。

因为这两个方法都可以重写,如果是自己的类,那么可以灵活重写,如果是jdk自己的类,那就要看他到底有没有重写这两个方法。

我们以String类的equlas方法为例:我们都知道,如果equlas方法如果没有重写,那就继承Object类的equlas方法,默认比较的是两个对象的内存地址,如果重写了,那就根据我们自己重写的规则来比较两个对象是否相等。

如下是jdkString类中自己重写的equals方法,


 public boolean equals(Object anObject) {
    // 如果两个String类型的对象内存地址相等直接返回true
        if (this == anObject) {
            return true;
        }
       // 如下做的操作就是比较两个字符串中的每一个char类型的数据,如果都完全匹配,那么就是返回true,如果有一个不相同,直接返回false,并且两个字符串的长度要相等,如果不相同,那么肯定也就不可能值一样了嘛
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

再看下String的hashcode方法:就是我们上面刚刚讲过的那个方法


 public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

1:如果两个String类型的对象内存地址相等直接返回true

2:比较两个字符串中的每一个char类型的数据,如果都完全匹配,那么就是返回true,如果有一个不相同,直接返回false,并且两个字符串的长度要相等,如果不相同,那么肯定也就不可能值一样了嘛

由此可以看出,equals方法是否返回true跟hashcode方法没有半毛钱关系嘛。

接下来我们看下,我们自定义的对象,我创建一个User类,里面有属性id和name


public class User {
    int id;
    String name;

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }


}

在没有重写hashcode方法和equals方法的情况下进行比较:


 User user1 = new User();
        User user2 = new User();

        System.out.println(user1.hashCode());
        System.out.println(user2.hashCode());
        System.out.println(user1.equals(user2));

在这里插入图片描述

解答:因为我们没有重写,这两个方法都是继承自Object类的,所以呢?比较的是内存地址,因为我们是通过new的方式去创建的两个user对象,那么他们的内存地址肯定是不相同的,所以直接返回false,而hashcode方法是java的底层语言c++来写的,具体他内部是怎么实现的,封装了,我也就不得而知了,后面再了解,有的人说是跟内存地址相关,但是具体我没有看到具体实现,也不敢苟同,有的东西,需要自己不断的去摸索,自己亲自实践,才是真的,不要相信别人说的。

好的,接下来我们重写User类的hashcode方法:


public class User {
    int id;
    String name;



    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }



    @Override
    public int hashCode() {
        return Objects.hash(id, name);
    }
}

在这里插入图片描述

可以看到的是,我们两个User对象的hashcode方法返回的hash值是完全一致的,但是通过equals方法进行比较,还是false,所以说,两个对象的hashcode方法返回的hash值相同,equlas也一定返回true是完全不成立的,直接推翻。

接下来我们再次重写equlas方法,此时我们规定,只要两个对象的id和name都相同,那么这两个对象就是同一个对象。并且删除掉刚刚我们重写的hashcode方法。


public class User {
    int id;
    String name;

    public User(int i, String name) {
        this.id = id;
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return id == user.id &&
                name.equals(user.name);
    }


}

在这里插入图片描述

通过运行结果,我们可以看到,hashcode方法返回的hash值不一致,但是我们的equlas方法依旧返回的是true,因为这个equlas方法是我们重写过了,在调用的时候,就不在去掉Object的equlas方法,进行比较内存地址,而是按照我们的重写规则:如果两个user对象的id和name相同,那么就是同一个对象,所以到这里,你是不是就具体的理解了hashcode方法个equlas之间的关系呢?

如果还是不明白,那再看一次,我们现在把User类的equlas方法和hashcode方法都写上,但是呢?我会创建两i不同的User对象(也就是id和name都不一样)。


public class User {
    int id;
    String name;

    public User(int i, String name) {
        this.id = id;
        this.name = name;
    }


    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return id == user.id &&
                name.equals(user.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name);
    }
}

在这里插入图片描述

由此可以看到,虽然hashcode方法返回的hash值相同,但是通过equlas方法进行比较,返回的直接就是false。

这里我们说的有点啰嗦了哈,本来三言两语就可以说清楚的,但是怕新手朋友不理解,所以就多啰嗦了几句,这个文章是我个人的理解,如果有不正确的希望你多参考书以及官网进行比对,毕竟眼见为实嘛,我也不敢完全保证我就是对的。

到此这篇关于详解Java中的hashcode的文章就介绍到这了,更多相关Java hashcode内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

详解Java中的hashcode

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Java中==与equals()及hashcode()三者之间的关系详解

最近也是在读Hollis的《深入理解Java核心技术》里面一节讲到了equals()和hashcode()的关系,对于这个高频面试点,咱们需要认真理清一下几者之间的关系
2022-11-13

如何Java中的hashCode()方法

本篇内容主要讲解“如何Java中的hashCode()方法”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何Java中的hashCode()方法”吧!Object 类中就包含了 hashCode
2023-06-15

Java中hashcode的示例分析

小编给大家分享一下Java中hashcode的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!java基本数据类型有哪些Java的基本数据类型分为:1、整数
2023-06-14

java中重写equals()方法的同时要重写hashcode()方法(详解)

object对象中的 public boolean equals(Object obj),对于任何非空引用值 x 和 y,当且仅当 x 和 y 引用同一个对象时,此方法才返回 true;注意:当此方法被重写时,通常有必要重写 hashCod
2023-05-31

Java中hashCode的作用是什么

本篇文章给大家分享的是有关Java中hashCode的作用是什么,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。hashcode方法返回该对象的哈希码值。支持该方法是为哈希表提供
2023-06-03

Java中hashCode方法怎么用

这篇文章主要介绍“Java中hashCode方法怎么用”,在日常操作中,相信很多人在Java中hashCode方法怎么用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java中hashCode方法怎么用”的疑
2023-06-29

hashCode在Java项目中的作用有哪些

本篇文章为大家展示了hashCode在Java项目中的作用有哪些,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。详解Java中hashCode的作用以下是关于HashCode的官方文档定义:hashc
2023-05-31

Java中 hashcode方法的作用是什么

这期内容当中小编将会给大家带来有关Java中 hashcode方法的作用是什么,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。Java可以用来干什么Java主要应用于:1. web开发;2. Android
2023-06-14

Java中hashCode()与equals()有什么不同

这期内容当中小编将会给大家带来有关Java中hashCode()与equals()有什么不同,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。equals()方法equals是Object类提供的方法之一,众
2023-05-31

java中重写equals和重写hashCode()

java中重写equals和重写hashCode()记得在刚上初一的时候,第一堂数学课学的是集合,那时候我知道了集合是不允许重复元素存在的。hashCode 方法用于散列集合的查找,equals 方法用于判断两个对象是否相等。为什么重写了
2023-05-31

java中hashcode和equals有什么不同

在Java中,hashCode()方法和equals()方法是用于比较对象的两种不同方式。hashCode()方法是Object类中的一个方法,在所有的Java对象中都有。它返回一个int类型的哈希码值,用于表示对象的唯一性。hashCod
2023-10-19

Java中怎么重写及应用hashCode

这篇文章主要介绍了Java中怎么重写及应用hashCode的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Java中怎么重写及应用hashCode文章都会有所收获,下面我们一起来看看吧。回顾equals方法我们先
2023-06-27

Java 中HashCode作用_动力节点Java学院整理

第1 部分 hashCode的作用  Java集合中有两类,一类是List,一类是Set他们之间的区别就在于List集合中的元素师有序的,且可以重复,而Set集合中元素是无序不可重复的。对于List好处理,但是对于Set而言我们要如何来保证
2023-05-31

hashcode方法如何在Java项目中使用

这篇文章给大家介绍hashcode方法如何在Java项目中使用,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。哈希表这个数据结构想必大多数人都不陌生,而且在很多地方都会利用到hash表来提高查找效率。在Java的Obje
2023-05-30

java Object的hashCode方法怎么使用

这篇文章主要讲解了“java Object的hashCode方法怎么使用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“java Object的hashCode方法怎么使用”吧!1. 背景介绍
2023-06-22

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录