`

hashMap怎么保证hash一致性的

 
阅读更多

学Java的都知道hashMap的底层是“链表散列”的数据结构也也可以说是hash表。在put的实话先根据key的hashcode重新计算hash值的,而我们又知道hash是一种算法。所以哈希码并不是完全唯一的。

查看哈希码百科:

 

null

 

哈希表可以说就是数组链表,底层还是数组但是这个数组每一项就是一个链表

一:为什么说hashmap的put方法是根据key进行hashcode计算的呢?

查看源码:

 

null

 

 

在查看hash方法,如下:

 

null

 

查看putVal方法:

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,

boolean evict) {

Node [] tab; Node p; int n, i;

if ((tab = table) == null || (n = tab.length) == 0)

n = (tab = resize()).length;

if ((p = tab[i = (n - 1) & hash]) == null)

tab[i] = newNode(hash, key, value, null);

else {

Node e; K k;

if (p.hash == hash &&

((k = p.key) == key || (key != null && key.equals(k))))

e = p;

else if (p instanceof TreeNode)

e = ((TreeNode )p).putTreeVal(this, tab, hash, key, value);

else {

for (int binCount = 0; ; ++binCount) {

if ((e = p.next) == null) {

p.next = newNode(hash, key, value, null);

if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st

treeifyBin(tab, hash);

break;

}

if (e.hash == hash &&

((k = e.key) == key || (key != null && key.equals(k))))

break;

p = e;

}

}

if (e != null) { // existing mapping for key

V oldValue = e.value;

if (!onlyIfAbsent || oldValue == null)

e.value = value;

afterNodeAccess(e);

return oldValue;

}

}

++modCount;

if (++size > threshold)

resize();

afterNodeInsertion(evict);

return null;

}

二:hashmap怎么解决key的hash值冲突问题的?

 

null

 

上图是源码截图,说明:

1:初始化map的大小。默认是16

示例代码:HashMap map = new HashMap();

2:如果tab为空,就newNode一个放到链表中

示例代码:map.put("aa",1); 也就是图-1测试代码中的1

3:根据key算出的hash值如果存在,且key的值和map中已经存在的值equals了。所以就不处理。

如下图:

null

 

测试代码如图-1测试代码中的1和 2

4:如果p是TreeNode的子类进行putTreeValu

5:如果key的hash值和map中已经存在的key的hash相等且key不同的时候,如果数组该位置上没有元素,就直接将该元素放到此数组中的该位置上。

如图-1测试代码 1和4中key的hesh值都为3104

图-1测试代码

 

null

 

在来看下Node这个内部类:

 

null

 

三:在来看看怎么get方法

 

null

 

null

 

说明:

1:如果链表中第一个值的hash值和需要获取的key的hash值相等的话,就直接取出。

2:如果链表first.next !=null就循环查找链表中的key,知道查询到key.equals(k) 取出对应的值。

查看源码或许感觉不懂,那么画图来说明:

 

null

 

总结:

数据结构:哈希表可以说就是数组链表,底层还是数组但是这个数组每一项就是一个链表。

map的put方法:

1:new hashMap的时候初始化默认大小为16

2:当map.put("aa",1)的时候判断map没有值,就把aa算的hash值放到0X004的位置

3:当再次执行map.put("aa",1)的是计算aa的hash值为3104.此时在OX004的位置已经有数据了。进行判断存在的key和新put的key是否相同。相同不处理,值覆盖

4:执行map.put("aa",2)的时候key和已经存在的key相同就直接覆盖value了

5:执行map.put(3104,"cc")的时候,key的hash值也为3104.此时数组中OX004已经存在数据,判断key是否相同。发现3104和aa不相同【注:此时就发生了hash冲突】,那么就aa这个链表前面追加3104

6:执行map.put("bb","cc")。假设bb计算出的hash值是3105就存放在了OX005上。

其他依次类推

 

map的get方法:

当执行map.get("bb")的时候先计算出bb的hash值为3105在对应的位置(也就是0X005)取出第一个判断值是不是bb如果是就直接取出value.

当执行map.get("aa")的时候先计算出aa的hash值为3104,去对应的位置取出判断值(3104)不等于(aa)且还有next。就循环取出进行比较。

 

 

0
0
分享到:
评论

相关推荐

    一致性Hash简单实现

    一致性哈希(Consistent Hashing)是一种分布式哈希表(DHT)的算法,它主要应用于分布式缓存、负载均衡等场景,旨在解决在动态扩展或收缩系统规模时,尽量减少数据迁移的问题。在这个简单的实现中,我们将探讨如何...

    一致性哈希与Chord1

    【一致性哈希与Chord1】是一篇关于分布式哈希算法的文章,主要讨论了一致性哈希和普通哈希的区别,以及如何通过引入虚拟节点来优化一致性哈希的分布问题。 1. **普通哈希算法**: - Java中的`HashMap`类是一个典型...

    基于共享内存的hashmap

    3. 数据一致性:为了保证数据的一致性,可能需要使用诸如CAS(Compare and Swap)或其他无锁算法来更新HashMap中的数据。 4. 故障恢复:如果进程崩溃,如何保证其他进程可以正确地处理这种情况,避免数据丢失或损坏...

    HashMap-master.zip_hash

    此外,对于大型数据集,优化哈希函数以减少冲突和提高查询效率是关键,这可能涉及到动态调整数组大小、使用更复杂的哈希算法或者采用一致性哈希等策略。 总的来说,这个项目提供了一个实践理解哈希表和哈希函数的...

    HashMap和HashTable的区别和不同

    如果多个线程并发地访问并修改`HashMap`,则可能导致数据不一致性问题。为了在多线程环境中安全地使用`HashMap`,开发者需要自己负责同步,例如使用`Collections.synchronizedMap(new HashMap,V>())`创建线程安全的`...

    HashMap的数据结构

    HashMap的工作原理基于哈希函数,它将键(Key)转化为一个哈希码(Hash Code),这个哈希码用于确定键值对在数组中的位置。当两个不同的键经过哈希函数处理后得到相同的哈希码时,就会发生哈希碰撞。为了解决这个...

    Hashtable和HashMap的区别:

    相反,如果你的应用程序需要处理多线程并发问题,并且对线程安全性有严格要求,那么 `Hashtable` 或者通过 `Collections.synchronizedMap()` 包装后的 `HashMap` 更适合。了解这些区别有助于开发者在实际开发过程中...

    HashMap与ConcurrentHashMap面试要点.pdf

    ### HashMap和ConcurrentHashMap...综上所述,面试时通常会针对HashMap和ConcurrentHashMap的实现原理、它们的差异、以及在并发环境下如何保证数据的一致性和线程安全进行提问。了解这些知识点有助于在面试中脱颖而出。

    HashMap原理.docx

    这些类型的对象已经重写了`equals()`和`hashCode()`方法,确保了键对象的不可变性和哈希一致性,从而减少了哈希冲突的可能性。 ##### 3.2 初始化参数的选择 初始化HashMap时,可以通过指定初始容量和加载因子来...

    hashMap具体详解

    这个设计是为了在保证空间效率的同时,尽量减少哈希冲突的可能性。 4. 入库操作:当我们使用put()方法添加键值对时,首先计算键的哈希码,然后找到对应的桶(Bucket)。如果桶中没有其他键值对,就直接放入;如果有...

    Go-Golang无锁线程安全的HashMap为最快的读取访问进行了优化

    在多线程环境中,为了保证数据的一致性和正确性,通常需要引入锁机制,但这会增加额外的开销,降低并发性能。Go语言提供了通道(Channel)和原子操作(Atomic Operations)等原生并发工具,使得无锁实现成为可能。 ...

    java中HashMap详解

    - **字段属性**:包括`serialVersionUID`用于序列化一致性,`DEFAULT_INITIAL_CAPACITY`定义了默认初始容量(16),`MAXIMUM_CAPACITY`表示最大容量(2^30),`LOAD_FACTOR`是默认负载因子(0.75)。 4. **哈希桶...

    ConsistentHash:一致性hash算法的 java 和 C++ 实现

    在Java中实现一致性哈希,可以使用JDK自带的`java.util.HashMap`或者第三方库如Google的Guava库中的`com.google.common.hash.Hashing`类来计算哈希值。然后,为了实现环形结构,可以自定义一个`Node`类表示节点,并...

    深入Java集合学习系列:HashMap的实现原理

    在使用HashMap时,需要注意几个关键点:1) 键必须正确实现hashCode()和equals()方法,以确保哈希计算和比较的一致性;2) 避免使用null键和null值,因为HashMap的null键和null值有特殊含义;3) 考虑负载因子和初始...

    HashMap 概述 精讲 .md

    如果在多线程环境中使用,需要额外的同步措施来确保数据的一致性和安全性。 ### HashMap 和 HashTable 的区别 #### 相同点 - **线程安全性**:尽管HashMap是非线程安全的,但在某些情况下,两个类都会使用同步...

    集合常见面试题

    如何用TreeMap实现一致性hash? ConcurrentHashMap是如何在保证并发安全的同时提高性能? ConcurrentHashMap是如何让多线程同时参与扩容? LinkedBlockingQueue、DelayQueue是如何实现的? CopyOnWriteArrayList是...

    48-Java知识点 手写HashMap1

    此外,HashMap还有一个内部字段`modCount`,在ArrayList和HashMap中都有,用于记录结构修改的次数,主要用于并发控制,确保在多线程环境下数据的一致性。当多个线程同时修改HashMap时,`modCount`的检查可以防止并发...

    cpp-C仅头文件高性能并行Hashmap

    线程安全:在多线程环境下,为了保证数据一致性,我们需要确保对HashMap的操作是线程安全的。这通常通过使用互斥量(mutex)、原子操作(atomic)或者读写锁(read-write lock)等同步原语来实现。在C++中,`std::...

    c语言 hashmap

    哈希表(Hashmap)是一种常见的数据结构,它在计算机科学和编程...然而,实际应用中,可能还需要考虑其他因素,如线程安全、内存效率和数据一致性。理解这些原理并实践,对于提升C语言编程能力及数据结构掌握至关重要。

    源码解析jdk7.0集合(3):HashMap的底层实现原理.pdf

    - **键的equals和hashCode方法**:由于HashMap是根据键的hashCode来计算索引的,因此键对象需要合理重写equals和hashCode方法,保证哈希的一致性和准确性。 #### 七、结语 通过深入解析HashMap在JDK 7.0中的底层...

Global site tag (gtag.js) - Google Analytics