集合框架 - HashSet和HashMap实现原理

本文详细探讨了Java中的HashSet和HashMap的实现原理。HashMap基于数组加链表/红黑树的存储结构,当bucket填充率达到负载因子时进行resize。put方法通过计算index并处理冲突来插入元素,当链表过长则转为红黑树。get方法通过hashCode定位bucket,再用equals方法找到对应节点。resize过程保证元素在新表中的位置要么不变,要么移动2的幂次位。
摘要由CSDN通过智能技术生成

HashSet的实现


HashSet是基于HashMap实现的,只使用HashMap的key来实现各种特性,用PRESENT 构造一个虚假的value。所以HashSet判断两个Key是否相等的机制和HansMap是一模一样的:equals返回true并且和hashCode返回值相同。下面是HashSet的部分实现,看代码:
private transient HashMap<E,Object> map;
// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();

public boolean add(E e) {
    return map.put(e, PRESENT)==null;
}
 
public boolean remove(Object o) {
    return map.remove(o)==PRESENT;
}
 
public boolean contains(Object o) {
    return map.containsKey(o);
}
 
public int size() {
    return map.size();
}

HashMap详解


简单来说,HashMap是一个数组加链表的存储结构。添加的时候先将元素放到bucket当中,当key冲突的时候会通过链表链接起来。查找的时候先计算index去查找,第一次没有命中就去遍历链表,直到找到为止。HaspMap是无序的,即遍历结果的次序可能和插入的次序不同。要想遍历的时候按插入次序输出,请使用LinkedHashMap(链表结构)。


两个重要的参数

在HashMap中有两个很重要的参数,容量(Capacity)和负载因子(Load factor)。简单的说,Capacity就是bucket的大小,Load factor就是bucket填满程度的比例。如果对迭代性能要求很高的话不要把capacity设置过大,也不要把load factor设置过小。当bucket中的entries的数目大于capacity * load factor时就需要调整bucket的大小为当前的2倍。

put方法的实现

put函数大致的思路为:

  • 对key的hashCode()做hash,然后再计算index;

  • 如果没碰撞直接放到bucket里;

  • 如果碰撞了,以链表的形式存在bucket后面;

  • 如果碰撞导致链表过长(大于等于TREEIFY_THRESHOLD),就把链表转换成红黑树;

  • 如果节点已经存在就替换old value(保证key的唯一性);

  • 如果bucket满了(超过load factor*current capacity),就要resize。

get方法的实现

get的大致思路如下:

  1. bucket里的第一个节点,直接命中;

  2. 如果有冲突,则通过key.equals(k)去查找对应的entry;

  3. 若为树,则在树中通过key.equals(k)查找,时间复杂度为O(logn);

  4. 若为链表,则在链表中通过key.equals(k)查找,时间复杂度为O(n)。

resize的实现

当put时,如果发现目前的bucket占用程度已经超过了Load Factor所希望的比例,那么就会发生resize。在resize的过程,简单的说就是把bucket扩充为2倍,之后重新计算index,把节点再放到新的bucket中。resize的注释是这样描述的:

Initializes or doubles table size. If null, allocates in accord with initial capacity target held in field threshold. Otherwise, because we are using power-of-two expansion, the elements from each bin must either stay at same index, or move with a power of two offset in the new table.

大致意思就是说,当超过限制的时候会resize,然而又因为我们使用的是2次幂的扩展(指长度扩为原来2倍),所以,元素的位置要么是在原位置,要么是在原位置再移动2次幂的位置。


更多详情:Java HashMap的工作原理及实现



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值