首页 > 编程知识 正文

hashmap的原理(hashmap get原理)

时间:2023-05-03 21:22:58 阅读:1052 作者:862

概念

-hashnmap是基于地图界面实现的。元素存储为键值对,键和值都可以为空。因为键不允许重复,所以只能有一个键为空。

-HaasnMap是无序且不重复的,而HashMap是线程不安全的。

-JDK7HashMap的数据结构是:数组链表。

-JDK8HashMap的数据结构是:数组链表红黑树。

存储的优点

-数组的特点:查询效率高,插入删除效率低。

-链表的特点:查询效率低,插入删除效率高。

-利用HasnMap底部的array plus(链表或红黑树)的结构,完美解决了数组和链表的问题,使得查询、插入和删除的效率非常高。

-HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap HashMap

00-1010调用K的hasnCode()方法获取哈希值;元素存储的索引是通过模hashcode值和数组长度得到的。

此时有两种情况。

1.下标位置没有元素,直接输入元素。

2.对于已有的元素,判断该位置的元素是否等于当前元素,使用equals进行比较(默认是比较两个对象的地址)。如果两个元素相等,则直接覆盖;如果它们不相等(Hash冲突),则使用链表结构将元素存储在原始元素下(如果已经有链表,则将其插入链表末尾),每个元素节点都有指向下一个节点的next属性,这将数组结构更改为数组链表;由于链表中的元素太多会影响搜索效率,当链表中的元素数量达到8个时,链表存储的使用将改为红黑树存储(当红黑树上的节点数量少于6个时,红黑树将再次变为单向链表数据结构)。原因是红黑树是一个平衡的二叉树,搜索性能比聊天列表高。

00-1010-首先调用K的hashCode()方法获取哈希值,并通过哈希算法将其转换为数组的下标。

-哈希值转换为数组下标后,通过数组定位下标位置。如果改变的位置没有任何东西,范围为空;如果在这个位置有一个单向链表,那么比较参数k和单向链表上每个节点的k是否相等。如果all等于return false,则返回null。如果一个节点的k和参数k通过equals返回true,那么这个节点的值就是要获得的值。

首先将k、v封装到Node对象当中(节点)

-HashMap有两个重要参数,初始容量大小和负载系数。当HashMap初始化时,使用默认的构造方法,将返回一个空表,然后hold(扩展阈值)为0。因此,首次扩展时,默认值为16,默认情况下负载系数为0.75。将阵列容量乘以负载系数,得到一个值。一旦数组中存储的元素数量超过该值,将调用rehash方法来使数组容量翻倍,阈值也将翻倍。

-扩展时会生成一个新数组,需要重新计算所有原始数据,并将哈希码值重新分配到新数组中,因此扩展操作会消耗大量性能。因此,如果您知道要存储的数据量相对较大,则可以在创建时指定相对较大的数据容量。

-还可以扩展为一个问题,HashMap应该先插入还是先扩展:HashMap初始化,第一次插入数据时,先进行大小调整扩展,再插入数据,然后每当插入的数据数量达到阈值时,就进行大小调整,此时先插入数据,再调整大小。

HashMap中的展开是在元素插入之前还是之后?

在JDK1.7中,在插入元素之前进行扩展,在JDK1.8中,先添加元素,然后判断扩展。

当元素超过阈值时,存储容量是否会扩大?

在JDK1.7中不一定,只有当存储元素超过阈值并且当前存储位置不为空时,电容才会

00-1010

HashMap取值的实现

-Hashmap是非线程安全的,HashTable是线程安全的。Hashtable的实现方法增加了synchronized关键字,保证了线程同步,所以HashMap的性能相对会更高。如果我们平时使用hashmap的时候没有特殊要求,建议使用HashMap。如果我们在多线程环境中使用hashmap,

HashMap需要使用Collections.synchronizedMap()方法来获取线程安全的集合。

-哈希表的键可以为空,哈希表的键不能为空。

-HashMap是Map接口的实现,HashTable实现Map接口和Dictionary抽象类。

hashmap的初始容量是16,Hashtable的初始容量

量为 11 ,两者的填充因子默认都是 0.75 ,HashMap扩容时是当前容量翻倍即:capacity * 2,- Hashtable扩容时是容量翻倍+1即:capacity * 2+1

HashMap中的hashcode怎么生成

调用对象key的hashCode方法,再对这个hashcode方法进行一些右移以及异或运算(使的hashCode的高位和低位都参与到运算中);通过右移和异或运算可以使hashMap的散列化更强,提高hashMap的get方法的效率

为什么使用HashCode

HashCode的存在主要是为了查找的快捷性, HashCode是用来在散列存储结构中确定对象的存储地址的 ( 用hashcode来代表对象在hash表中的位置 ) , hashCode存在的重要的原因之一就是在HashMap(HashSet其实就是HashMap)中使用(其实Object类的hashCode方法注释已经说明了),HashMap之所以速度 快 ,因为他使用的是 散列表 ,根据key的hashcode值生成数组下标(通过内存地址直接查找,不需要判断,但是需要多出很多内存,相当于以空间换时间)

- equals方法和hashcode的关系

归纳总结:

- 若重写了equals(Object obj)方法,则有必要重写hashCode()方法

- 若两个对象equals(Object obj)返回true,则hashCode()有必要也返回相同的int数

- 若两个对象equals(Object obj)返回false,则hashCode()不一定返回不同的int数

- 若两个对象hashCode()返回相同int数,则equals(Object obj)不一定返回true

- 若两个对象hashCode()返回不同int数,则equals(Object obj)一定返回false

- 同一对象在执行期间若已经存储在集合中,则不能修改影响hashCode值的相关信息,否则会导致内存泄露问题

key为null怎么办

key为null的时候,只会放在hashMap的0位置(即key的hashCode为0,对数组长度取余后的下标也是0),不会有链表 在HashMap源码中对put方法对null做了处理,key为null的判断后进入putForNullKey(V value)这个方法,李里面for循环是在talbe[0]链表 中查找key为null的元素,如果找到,则将value重新赋值给这个元素的value,并返回原来的value。如果没找到则将这个元素添加到talbe[0]链表的表头

```c

/**

* HashMap的put方法

*/

public V put(K key, V value) {

if (table == EMPTY_TABLE) {

inflateTable(threshold);

}

// key为null调用putForNullKey(value)

if (key == null) return putForNullKey(value);

int hash = hash(key);

int i = indexFor(hash, table.length);

for (Entry<K,V> e = table[i]; e != null; e = e.next) {

Object k;

if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {

V oldValue = e.value;

e.value = value;

e.recordAccess(this);

return oldValue;

}

}

modCount++;

addEntry(hash, key, value, i);

return null;

}

/**

* Offloaded version of put for null keys

*/

private V putForNullKey(V value) {

// for循环处理key为空的情况

for (Entry<K,V> e = table[0]; e != null; e = e.next) {

if (e.key == null) {

V oldValue = e.value;

e.value = value;

e.recordAccess(this);

return oldValue;

}

}

modCount++;

addEntry(0, null, value, 0);

return null;

}

```

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。