IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> HashSet底层源码解读 -> 正文阅读

[数据结构与算法]HashSet底层源码解读

推荐看完HashSet链表模拟和HashSet扩容机制再来看本文章

HashSet底层源码解读01

import java.util.HashSet;
?
public class HashSetSource {
 ? ?public static void main(String[] args) {
?
 ? ? ? ?HashSet hashSet = new HashSet();
 ? ? ? ?hashSet.add("Java");
 ? ? ? ?hashSet.add("PHP");
 ? ? ? ?hashSet.add("Java");
 ? ? ? ?System.out.println(hashSet);
?
 ?  }
?
}
/*
源码解读:
1.执行 HashSet() 方法
public HashSet() {
 ? ?map = new HashMap<>();
}
2.执行 add() 方法
public boolean add(E e) {
 ? ?return map.put(e, PRESENT)==null;  //private static final Object PRESENT = new Object();
}
3.执行 put() 方法,该方法会执行 hash(key) 得到key对应的hash值 算法(h = key.hashCode()) ^ (h >>> 16);
public V put(K key, V value) {//key = "Java" value = PRESENT 共享
 ? ?return putVal(hash(key), key, value, false, true);
}
3.1 hash(key)方法
static final int hash(Object key) {
 ? ?int h;
 ? ?return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
4.
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
 ? ? ? ? ? ? ? boolean evict) {
 ? ?Node<K,V>[] tab; Node<K,V> p; int n, i; //定义了辅助变量
 ? ?//table 就是 HashMap 的一个数组,类型就是 Node
 ? ?//if 语句表示如果当前table 是null,或者 大小=0
 ? ?//就是第一次扩容,到16个空间
 ? ?if ((tab = table) == null || (n = tab.length) == 0)
 ? ? ? ?n = (tab = resize()).length;
 ? ?//(1)根据key,得到 hash 去计算该key应该存放到table表的那个索引位置
 ? ?//并把这个位置的对象,赋给16个空间
 ? ?//(2)判断p 是否为null
 ? ?//(2.1) 如果p为null,表示还没有存放元素,就创建一个Node(key="Java",value=PRESENT)
 ? ?//(2.2) 就放在该位置
 ? ?if ((p = tab[i = (n - 1) & hash]) == null)
 ? ? ? ?tab[i] = newNode(hash, key, value, null);
 ? ?else {
 ? ? ? ?//开发技巧提示:定义变量是在需要局部变量(辅助变量)的地方创建,
 ? ? ? ?Node<K,V> e; K k;
 ? ? ? ?//如果当前索引位置对应的链表的第一个元素和准备添加的key的hash一样
 ? ? ? ?//并且满足  下面两个条件之一
 ? ? ? ?//(1)准备加入的key 和 p 指向的Node 节点的 key 是同一个对象
 ? ? ? ?//(2) p 指向的Node 结点的 key 的equals() 和准备加入到的 key 比较后相同
 ? ? ? ?//就不能加入
 ? ? ? ?if (p.hash == hash &&
 ? ? ? ? ? ?((k = p.key) == key || (key != null && key.equals(k))))
 ? ? ? ? ? ?e = p;
 ? ? ? ?//再判断 p 是不是一颗红黑树
 ? ? ? ?//如果是一颗红黑树,就调用 putTreeVal , 来进行添加
 ? ? ? ?else if (p instanceof TreeNode)
 ? ? ? ? ? ?e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
 ? ? ? ?else { //如果table 对应索引位置,已经是一个链表了,就使用for循环比较
 ? ? ? ? ? ? ? ?//(1) 依次和该链表的每一个元素比较后都不相同,则加入到该链表的最后
 ? ? ? ? ? ? ? ?// ?  注意:在把元素添加到链表后,立即判断 该链表是否已经达到八个结点
 ? ? ? ? ? ? ? ?// ?  ,就调用treeifyBin() 对当前这个链表进行树化(转成红黑树)
 ? ? ? ? ? ? ? ?// ?  注意:在转换程红黑树,要进行判断,判断条件如下
 ? ? ? ? ? ? ? ?// ?  if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
 ? ? ? ? ? ? ? ?// ? ? ? ?  resize();
 ? ? ? ? ? ? ? ?// ?  如果上面条件成立,先table扩容,
 ? ? ? ? ? ? ? ?// ?  只有上面条件不成立时,才进行转成红黑树
 ? ? ? ? ? ? ? ?//(2) 依次和该链表的每一个元素比较的过程中,如果有相同的情况,就直接 break
 ? ? ? ? ? ?for (int binCount = 0; ; ++binCount) {
 ? ? ? ? ? ? ? ?if ((e = p.next) == null) {
 ? ? ? ? ? ? ? ? ? ?p.next = newNode(hash, key, value, null);
 ? ? ? ? ? ? ? ? ? ?if (binCount >= TREEIFY_THRESHOLD(8) - 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;
 ? ?//判断是否需要扩容
 ? ?//size 就是我们每加入一个结点Node(k,v,h,next),size++
 ? ?if (++size > threshold)
 ? ? ? ?resize();  //扩容
 ? ?//空方法 留给子类实现
 ? ?afterNodeInsertion(evict);
 ? ?return null;
}
 */

HashSet底层源码解读02

  • HashSet底层是HashMap,第一次添加时,table数组扩容到 16,临界值(threshold)是 16*加载因子(loadFactor)是0.75 = 12

  • 如果table数组使用到了临界值 12,就会扩容到 16 * 2 = 32,新的临界值就是 32 * 0.75 = 24,就会扩容到 32 * 2 = 64,以此类推

  • 在Java 8 中,如果一天链表的元素个数到达 TREEIFY_THRESHOLD(默认是8),并且table大小 >= MIIN_TREEIFY_CAPACITY(默认64),就会进行树化(红黑树),否则任然采用数组扩容机制

    import java.util.HashSet;
    ?
    public class HashSetIncrement {
     ? ?public static void main(String[] args) {
     ? ? ? ?HashSet hashSet = new HashSet();
    // ? ? ?  for (int i = 0; i <= 100; i++) {
    // ? ? ? ? ?  hashSet.add(i);
    // ? ? ?  }
    // ? ? ?  for (int i = 0; i <= 12; i++) {
    // ? ? ? ? ?  hashSet.add(new A(i));
    // ? ? ?  }
    ?
     ? ? ? ?for (int i = 0; i <= 7; i++) { //在table链表的某一条链表上增加了7个A对象
     ? ? ? ? ? ?hashSet.add(new A(i));
     ? ? ?  }
    ?
     ? ? ? ?for (int i = 0; i <= 7; i++) { //在table链表的某一条链表上增加了7个B对象
     ? ? ? ? ? ?hashSet.add(new B(i));
     ? ? ?  }
    ?
     ? ? ? ?/*
     ? ? ? ? ? ?当我们向hashset增加一个元素, -> Node -> 加入table , 就算是增加了一个,也触发扩容
     ? ? ? ? */
    ?
     ?  }
    }
    class A{
     ? ?private int n;
    ?
     ? ?public A(int n) {
     ? ? ? ?this.n = n;
     ?  }
    ?
    ?
     ? ?@Override
     ? ?public int hashCode() {
     ? ? ? ?return 100;
     ?  }
    }
    class B{
     ? ?private int n;
    ?
     ? ?public B(int n) {
     ? ? ? ?this.n = n;
     ?  }
    ?
     ? ?@Override
     ? ?public int hashCode() {
     ? ? ? ?return 200;
     ?  }
    }

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-01-14 02:14:08  更:2022-01-14 02:14:59 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 18:46:36-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码