HashMap集合底层方法的实现原理

HashMap集合

HashMap集合的特点

首先我们知道HashMap集合底层是一个由数组+链表+红黑树的一个结构(JDK8更新之后),也可以说是哈希表
HashMap集合有几个特点

  1. 无序且不可重复
  2. 放在hashMap集合中的key和value都可以为null

在Java8中,将HashMap底层由原先的Entry节点更改为现在的Node节点,插入格式也由头插法变为了尾插法,之前的Java7的头插法在插入的时候会将原位置的数据向后移一位,再插入数据到该位置;有可能出现逆序和环形链表死循环的问题。Java8改为尾插法解决了这一问题,增加了效率

集合中的key是不能重复的而且无序

// public class HashMapTest01 {
    public static void main(String[] args) {
        Map<Integer,String> map = new HashMap<>();
        map.put(1111,"张三");
        map.put(2222,"李四");
        map.put(3333,"赵六");
        map.put(1111,"国王");//key重复的时候value会自动覆盖

        System.out.println(map.size());//3

        Set<Map.Entry<Integer, String>> entries = map.entrySet();
        for(Map.Entry<Integer,String> s : entries){
            System.out.println(s.getKey() + s.getValue());
            //验证HashMap集合中的key部分元素:无序不可重复
        }

    }
}
输出结果:
		3
		3333赵六
		1111国王
		2222李四

HashMap底层的源代码(只贴出需要的属性)
下面展示一些 内联代码片

// A code block
var foo = 'bar';
// public class HashMap{
    //HashMap底层实际上就是一个数组
    Node<K,V>[] table;

    //静态内部类HashMap,Node
    static class Node<K,V>{
    final int hash;// 哈希值(哈希值是key的hashcode()方法执行结果。hash值通过哈希函数,可以转化为数组的下标)
    final k key;  //存储到Map集合中的key
    V  value; //存储到Map集合中的value
    Node<K,V> next;//下一个节点的内存地址
    }

以上是HashMap中比较重要的几个属性
我们用put方法和get方法来举例说明再存储的时候底层所进行的内容
map.put(K,V)方法底层实现原理
第一步:先将(K,B)封装为一个Node对象
第二步:底层会调用key和hashcode()方法来计算出hash值,再通过哈希函数/哈希算法计算出hash值所对应的数组下标是多少
第三步:找到下标之后会先判断,如果下标位置没有任何元素,那么直接将Node对象插入到这个位置上。如果该位置有链表,此时k会和链表上的每一个key进行equals()方法比较,如果equals方法返回true,那么就会用新的value值覆盖老的value值,如果equals方法返回false,那么就会再链表的尾部插入这个Node对象。get()方法也是同理了

从以上的步骤可以看出,HashMap在put元素的时候,key会先后调用hashcode()和equals()方法
那么这两个方法为什么需要同时重写呢,我们通过代码来讲解一下

// 
public class HashMapTest02 {
    	public static void main(String[] args) {
        Student s1 = new Student("张三");
        Student s2 = new Student("张三");
        /*//重写equals方法之前是false
        System.out.println(s1.equals(s2));//false*/

        //重写equals方法之后是true
        System.out.println(s1.equals(s2));//true

        System.out.println("s1的hashcode值" + s1.hashCode());//s1的hashcode值1735600054
        System.out.println("s2的hashcode值" + s2.hashCode());//s2的hashcode值21685669
        
	//没有重写hashcode方法
        Set<Student> set =new HashSet<>();
        set.add(s1);
        set.add(s2);
        System.out.println(set.size());//这个结果按说应该是1,但是结果是2。显然不符合hashSet集合的规范
        
        输出结果
        true
	s1的hashcode值774920
	s2的hashcode值774920
	2
	    }
	}

以上代码只是简单的new了一个Student对象,来讲解一下为什么要同时重写hashcode()方法和equals()方法
最终结论:放在HashMap集合中的key和hashSet集合中的元素
必须同时重写hashcode和equals方法
最后HashMap有一个扩容的机制,需要大家了解一下 面试的时候可能会问到。
HashMap集合默认的初始化容量为16,负载因子为0.75
当数组的的容量达到 初始化容量 * 负载因子
会调用resize()方法进行扩容 扩容为原来的2倍.

还有就是ConcurrentHashMap了感兴趣的可以去了解一下,现在基本都在用这个实现类因为这个实现类并发控制采用的是synchronized+CAS来操作,采用的是分段上锁,而不是像hashtable一样在方法上上锁,效率很低。数据结构和HashMap一样。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值