转自:https://blog.csdn.net/qq_21430549/article/details/52225801

1.从HashMap说起

我们知道Map以键值对的形式来存储数据。有一点值得说明的是,如果要使用我们自己的类作为键,我们必须同时重写hashCode() 和 equals()两个方法。HashMap使用equals方法来判断当前的键是否与表中的键相同。equals()方法需要满足以下5个条件

  • 自反性 x.equals(x) 一定返回true
  • 对称性 x.equals(y)返回true,则y.equals(x) 也返回true
  • 传递性 x.equals(y)返回true,y.equals(z)返回true,则x.equals(y)返回true
  • 一致性 如果对象中的信息没有改变,x.equals(y)要么一直返回true,要么一直返回false
  • 对任何不是null的x,想x.equals(null)一定返回false

2.散列

散列的价值在于速度。

假如键没有按照一定的顺序进行保存,那么查询的时候就只能按照顺序进行线性查询,然而,线性查询是最慢的查询方式。所以,将键值按照一定的顺序排序,并且使用二分查找能购有效的提升速度。散列在此之上,更近一步,他将键保存在数组中(数组的查询速度最快),用数组来表示键的信息,但是由于Map的容量是可变的,而数组的容量是不变的。要解决这个问题,数组中存的并不是键本身,而是键对象生成的一个数字,将其作为数组的下标,这个数字就是散列码。

而这种办法所产生的问题就是下标重复。而我们的解决办法就是配合equals来确定键值。

查询的过程首先就是计算散列码,然后用散列码来查询函数(下标),通常,我们的数组中保存的是值的list,因此,我们计算出散列码之后,通过下表取到的对应部分的list,然后通过equals就可以快速找到键值。

3.HashCode

hashCode函数是用来生成散列码的,我们看看Integer的计算方式(ps:我们自己的对象我们要选择自己的方式)

    public static int hashCode(int value) {
return value;
}
  • 1
  • 2
  • 3

这里不在多说,我们自己的类有自己的散列码实现就好。

4. 以HashMap的get方法来说明

    public V get(Object key) {
if (key == null) {
HashMapEntry<K, V> e = entryForNullKey;
return e == null ? null : e.value;
} int hash = Collections.secondaryHash(key);
HashMapEntry<K, V>[] tab = table;
for (HashMapEntry<K, V> e = tab[hash & (tab.length - 1)];
e != null; e = e.next) {
K eKey = e.key;
if (eKey == key || (e.hash == hash && key.equals(eKey))) {
return e.value;
}
}
return null;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • int hash = Collections.secondaryHash(key); 计算出散列码
  • HashMapEntry
            K eKey = e.key;
if (eKey == key || (e.hash == hash && key.equals(eKey))) {
return e.value;
}
  • 1
  • 2
  • 3
  • 4
  • 若地址相同,返回值,
  • 若hash值相等且equals返回true,返回值
  • 、、、、、、、、、、、、、、、、、、、
  • 二、理解hashCode()

    散列的价值在于速度:散列使得查询得以快速执行。由于速度的瓶颈是对“键”进行查询,而存储一组元素最快的数据结构是数组,所以用它来代表键的信息,注意:数组并不保存“键”的本身。而通过“键”对象生成一个数字,将其作为数组的下标索引。这个数字就是散列码,由定义在Object的hashCode()生成(或成为散列函数)。同时,为了解决数组容量被固定的问题,不同的“键”可以产生相同的下标。那对于数组来说?怎么在同一个下标索引保存多个值呢??原来数组并不直接保存“值”,而是保存“值”的 List。然后对 List中的“值”使用equals()方法进行线性的查询。这部分的查询自然会比较慢,但是如果有好的散列函数,每个下标索引只保存少量的值,只对很少的元素进行比较,就会快的多。

    不知道大家有没有理解我上面在说什么。不过没关系,下面会有一个例子帮助大家理解。不过我之前一直被一个问题纠结:为什么一个hashCode的下标存的会有多个值?因为hashMap里面只能有唯一的key啊,所以只能有唯一的value在那个下标才对啊。这里就要提出一个新的概念哈希冲突的问题,借用网上的一个例子:

    比如:数组的长度是5。这时有一个数据是6。那么如何把这个6存放到长度只有5的数组中呢。按照取模法,计算6%5,结果是1,那么就把6放到数组下标是1的位置。那么,7就应该放到2这个位置。到此位置,哈希冲突还没有出现。这时,有个数据是11,按照取模法,11%5=1,也等于1。那么原来数组下标是1的地方已经有数了,是6。这时又计算出1这个位置,那么数组1这个位置,就必须储存两个数了。这时,就叫哈希冲突。冲突之后就要按照顺序来存放了。所以这里Java中用的解决方法就是在这个hashCode上存一个List,当遇到相同的hashCode时,就往这个List里add元素就可以了。这才是hash原理的精髓所在啊!

java怎么计算散列码hashcode?的更多相关文章

  1. Java集合(7):散列与散列码

    散列的价值在于速度.我们使用数组来保存键的信息,这个信息并不是键本身,而是通过键对象生成一个数字(散列码),作为数组下标.由于数组的容量是固定的,而散列容器的大小是可变的,所以不同的键可以产生相同的数 ...

  2. java 散列与散列码探讨 ,简单HashMap实现散列映射表运行各种操作示列

    java 散列与散列码探讨 ,简单HashMap实现散列映射表运行各种操作示列 package org.rui.collection2.maps; /** * 散列与散列码 * 将土拔鼠对象与预报对象 ...

  3. Java散列和散列码的实现

    转自:https://blog.csdn.net/al_assad/article/details/52989525 散列和散列码   ※正确的equals方法应该满足的的条件: ①自反性:x.equ ...

  4. java 解决Hash(散列)冲突的四种方法--开放定址法(线性探测,二次探测,伪随机探测)、链地址法、再哈希、建立公共溢出区

    java 解决Hash(散列)冲突的四种方法--开放定址法(线性探测,二次探测,伪随机探测).链地址法.再哈希.建立公共溢出区 标签: hashmaphashmap冲突解决冲突的方法冲突 2016-0 ...

  5. Java 消息摘要 散列 MD5 SHA

    package xxx.common.util; import java.math.BigInteger; import java.security.MessageDigest; import jav ...

  6. java学习-sha1散列算法

    直接调用HashKit.sha1(String str)方法就可以了,,返回的是16进制的字符串长度是40, 也就是用md.digest()方法解析出来的字节数是160字节长度. 而MD5散列算法生成 ...

  7. Java解决Hash(散列)冲突的四种方法--开放地址法(线性探测,二次探测,伪随机探测)、链地址法、再哈希、建立公共溢出区

    最近时间有点紧,暂时先放参考链接了,待有时间在总结一下: 查了好多,这几篇博客写的真心好,互有优缺点,大家一个一个看就会明白了: 参考 1. 先看这个明白拉链法(链地址法),这个带源码,很好看懂,只不 ...

  8. 关于Java的散列桶, 以及附上一个案例-重写map集合

    为速度而散列: SlowMap.java说明了创建一个新的Map并不困难.但正如它的名称SlowMap所示,它不会很快,如果有更好的选择就应该放弃它.它的问题在于对键的查询,键没有按照任何特定的顺序保 ...

  9. Java 散列集笔记

    散列表 散列表(hash table)为每个对象计算一个整数,称为散列码(hash code). 若需要自定义类,就要负责实现这个类的hashCode方法.注意自己实现的hashCode方法应该与eq ...

随机推荐

  1. STM32的IO口灌入电流和输出驱动电流最大是多少?

    最大可以输出8mA,灌入20mA,但要保证所有进入芯片VDD的电流不能超过150mA,同样所有从VSS流出的电流也不能超过150mA. 详细请看STM32的数据手册中的相关内容. 例如,STM32F1 ...

  2. Mac 全局变量 ~/.bash_profile 文件不存在的问题

    不存在就新建呗~ $ cd ~/ $ touch .bash_profile $ open -e .bash_profile 然后输入以下内容 # set color的部分是配置iterm2的字体颜色 ...

  3. Jumpserver web界面跳板机

    Jumpserver.org 普通用户 仪表盘 查看主机 上传下载 访问官网 欢迎使用Jumpserver开源跳板机系统 帮助 Log out 查看资产 仪表盘 资产管理 查看资产 主机详细信息列表 ...

  4. memcache命令行

    memcache运行状态可以方便的用stats命令显示. 首先用telnet 127.0.0.1 11211  [quit 退出]这样的命令连接上memcache,然后直接输入stats就可以得到当前 ...

  5. 筛选git最后一次文件列表

    需要写一个小程序,列出出最后一次git提交的文件列表 命令如下: git log -1 --name-only 操作后,发现并不能完整的显示文件列表,查询google后,发现是git默认配置只显示90 ...

  6. 封面式 code-代码助手

    1  保存代码 2  搜索代码 3  生成网页 下载地址: http://gudianxiaoshuo.com

  7. layui的单选框

    <script type="text/html" id="radioTpl"> <input type="radio" n ...

  8. poj1182食物链--并查集

    动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A. 现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种.有人用两种说 ...

  9. Zabbix exp编写

    #/usr/bin/python #*-*coding=utf-8*-* import urllib logo = '''\n _____ _ _ _ _____ _ |__ /__ _| |__ | ...

  10. java 读写文件常用方法

    package study.bigdata; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; ...