Java HashMap底层原理_存储键值对底层过程 尚学堂150

https://www.sxt.cn/Java_jQuery_in_action/nine-hashmap-bottom.html 

https://www.bilibili.com/video/BV1ct411n7oG?p=151


目录

HashMap类的源码:

hashCode方法

 Integer类重写了hashCode方法


HashMap类的源码:

public class HashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable {......}

其中有:

transient Node<K,V>[] table;

table就是HashMap的核心数组结构,我们也称之为“位桶数组”(往里面装东西的)。

table是一个数组,它就是核心内容,他的类似是内部定义的一个类,本质上是链表的一个节点:

static class Node<K,V> implements Map.Entry<K,V> {
    final int hash;
    final K key;
    V value;
    Node<K,V> next;
    ......
}

其中,hash是哈希值,还有key对象、value对象,以及下一个节点next

这是一个单向链表,因为它没有上一个。


hashCode方法

每一个对象的hashCode是用它的地址生成的:


public class Test {
	public static void main(String[] args) {
		A a = new A();
		System.out.println(a.hashCode());
	}
}

class A{}

输出结果:

1449621165

该输出结果取决于它的地址。

这来自Object类的hashCode方法,Object类的hashCode方法源码:

public native int hashCode();

可以看到,这是调用了本地方法(native)。 


 Integer类重写了hashCode方法

Integer类重写了hashCode方法,把它的值直接返回了。

Integer类的hashCode方法:

    @Override
    public int hashCode() {
        return Integer.hashCode(value);
    }

其中,Integer.hashCode(value): 

    public static int hashCode(int value) {
        return value;
    }

举例:


public class Test {
	public static void main(String[] args) {
		Integer a = Integer.valueOf(123);
		System.out.println(a.hashCode());
	}
}

输出结果:

123


 每个对象调用hashCode方法后都会返回一串数字。


HashMap存储键值对的过程
key对象调用hashCode方法得到一个哈希码。

前面说的table数组的默认长度是16,后面也可以更大:

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

也就是要把key对象生成的哈希码与0-15对应起来。

一个最简单的方法,就是对16取余数它的余数就是0-15。

尽量要散,这样弄利用数组的特点,查询速度快。

注意不要把调用hashcode方法生成的哈希吗和HashMap类里面的hash方法算出的哈希值(hash值)混淆,这是2个东西。

hashcode是一个整数,我们需要将它转化成[0, 数组长度-1]的范围。我们要求转化后的hash值尽量均匀地分布在[0,数组长度-1]这个区间,减少“hash冲突”

           i. 一种极端简单和低下的算法是:

           hash值 = hashcode/hashcode;

           也就是说,hash值总是1。意味着,键值对对象都会存储到数组索引1位置,这样就形成一个非常长的链表。相当于每存储一个对象都会发生“hash冲突”,HashMap也退化成了一个“链表”。

           ii. 一种简单和常用的算法是(相除取余算法):

           hash值 = hashcode%数组长度

           这种算法可以让hash值均匀的分布在[0,数组长度-1]的区间。 早期的HashTable就是采用这种算法。但是,这种算法由于使用了“除法”,效率低下。JDK后来改进了算法。首先约定数组长度必须为2的整数幂,这样采用位运算即可实现取余的效果:hash值 = hashcode&(数组长度-1)。

JDK8中,HashMap在存储一个元素时,当对应链表长度大于8时,链表就转换为红黑树,这样又大大提高了查找的效率。

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值