集合源码解读

集合体系图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-baIB2EiL-1624602573916)(E:\Typora\QQ截图20210624120203.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nWk0RReo-1624602573917)(E:\Typora\QQ截图20210624120223.png)]

集合主要是两组,单列集合Collection和双列集合Map

集合实现类总结

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KXvTWNQ9-1624602573919)(E:\Typora\QQ截图20210624212653.png)]

Hash Set源码解读

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("set="+hashSet);}
}

hashset图片说明

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0TigK1gB-1624602573921)(E:\Typora\QQ截图20210622090808.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y8UxPKPC-1624602573922)(E:\Typora\QQ截图20210622094249.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f4li0XiJ-1624602573924)(E:\Typora\QQ截图20210622144311.png)]

###构造方法

    public HashSet() {map = new HashMap<>();  //底层是一个hashmap}

add方法

public boolean add(E e) { //e是添加的元素,例如Javareturn map.put(e, PRESENT)==null;
}

idea快捷键F4:在当前类中查找变量的来源,例如上述代码的PRESENT

private static final Object PRESENT = new Object();
//PRESENT只是一个对象,无法改变(static final),相当于占位符,占据put方法的value

put方法

public V put(K key, V value) { //key="java",value="PRESENT"return putVal(hash(key), key, value, false, true);//到了这个代码块不能点step into,会直接进入putVal,先进入hash(key),应该点击force step into,
}
hash值方法
static final int hash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);//hashCode方法是object类方法,可以重写该方法,为一个object获得一个hash值
}
putVal方法
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节点的数组,类型是Node[]if ((tab = table) == null || (n = tab.length) == 0)//如果table为空,resize为他分配默认的16个空间大小n = (tab = resize()).length;if ((p = tab[i = (n - 1) & hash]) == null)//根据hash值得到key应该存放在table表的哪个索引位置,并且把这个位置的对象赋值给p,p是该hash值的第一个元素//为空的话,表示没有存放元素,就创建一个node(key,value)//如果有相同的hash值了,得到的table索引位置就不为空。 tab[i] = newNode(hash, key, value, null);else {Node<K,V> e; K k;//一个开发技巧:在需要局部变量(辅助变量)的时候,再创建if (p.hash == hash &&//如果当前索引位置对应的链表的第一个元素和准备添加的key的hash值一样,并且满足下面两个条件之一:    //(1)准备加入的key和p指向的node节点的key是同一个对象//(2)p指向的node节点的key的equals()和准备加入的key比较后相同(针对对象比较),注意equals方法可以重写,自己定义规则。((k = p.key) == key || (key != null && key.equals(k))))e = p;else if (p instanceof TreeNode)//判断p是不是红黑树,是的话调用putTreeVal进行添加e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);else {//如果table对应索引位置,已经是一个链表,就使用for循环比较//(1)依次和链表的每一个元素比较后,都不相同,则加入链表//(2)如果有相同,则breakfor (int binCount = 0; ; ++binCount) {if ((e = p.next) == null) {//索引位置只有一个元素,直接放到后面p.next = newNode(hash, key, value, null);if (binCount >= TREEIFY_THRESHOLD - 1) // 把元素添加到链表后,立即判断该链表是否达到8个结点//达到就调用treeifyBin,对当前链表树化//注意,在转成红黑树前,要进行判断,判断条件://if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY(64))//             resize();//条件成立,先table扩容至64,条件不成立,才进行红黑树化。                      treeifyBin(tab, hash);break;}if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))break;//相同了直接breakp = e;//指向下一个}}if (e != null) { // existing mapping for keyV oldValue = e.value;if (!onlyIfAbsent || oldValue == null)e.value = value;afterNodeAccess(e);return oldValue;}}++modCount;if (++size > threshold)//threshold表示16乘加载因子0.75//size就是我们每加入一个结点node,size就会++,不管是加入链表还是tableresize();afterNodeInsertion(evict);//为hashmap子类存在的方法,于该add方法无关return null;//返回空代表成功
}

注意

如果我们要求对象的属性相同,则返回相同的hash值,我们应该重写hashcode方法

LinkedHashSet源码解读

public class LinkedHashSetSource {public static void main(String[] args) {LinkedHashSet linkedHashSet = new LinkedHashSet();linkedHashSet.add("AA");linkedHashSet.add(456);linkedHashSet.add(456);linkedHashSet.add(123);linkedHashSet.add("HSP");System.out.println("linkedHashSet"+linkedHashSet);}
}

输出linkedHashSet[AA, 456, 123, HSP]

LinkedHashSet加入顺序和取出顺序一致

构造方法

HashSet(int initialCapacity, float loadFactor, boolean dummy) {map = new LinkedHashMap<>(initialCapacity, loadFactor);
}

linkedHashSet底层是一个LinkedHashMap(hashmap的子类)

底层结构(数组table和 双向链表)

添加第一次时,直接将数组table扩容到16,数组是HashMapNode[]类型,存放元素类型是LinkedHashMapNode[]类型,存放元素类型是LinkedHashMapNode[]类型,存放元素类型是LinkedHashMapEntry

static class Entry<K,V> extends HashMap.Node<K,V> {Entry<K,V> before, after;Entry(int hash, K key, V value, Node<K,V> next) {super(hash, key, value, next);}
}

LinkedHashSet图片说明

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ofw044sV-1624602573924)(E:\Typora\QQ截图20210623163644.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-49AcV5d5-1624602573925)(E:\Typora\QQ截图20210623165315.png)]

add方法

public boolean add(E e) {return map.put(e, PRESENT)==null;
}

add方法和hashset一样。

HashMap源码解读

public class CollectionFor {public static void main(String[] args) {HashMap map = new HashMap();map.put("no1","饶冬章");map.put("no2","张无忌");map.put("no1","张三丰");System.out.println("map="+map);}
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QgQ02mjB-1624602573926)(E:\Typora\QQ截图20210624151344-1624519915560.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5DeLYKcO-1624602573927)(E:\Typora\QQ截图20210624163438.png)]

key如果重复了,会替换上一次的值

k-v 最后是HashMap$Node node = newNode(hash, key, value, null)

k-v为了方便程序员的遍历,还会创建EntrySet 集合,该集合存放的元素类型 Entry,而一个Entry对象就有k,v EntrySet<Entry<K,V>>

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D1NoshFF-1624602573927)(E:\Typora\QQ截图20210624153348.png)]

public Set<Map.Entry<K,V>> entrySet() {Set<Map.Entry<K,V>> es;return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;
}

entrySet方法返回的类型是Set<Map.Entry<K,V>>,要想得到Map.Entry<K,V>需要向下转型。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-380SrYJQ-1624602573928)(E:\Typora\QQ截图20210624171635.png)]

扩容机制

和hashset一样

HashTable解读

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DVh7wdAW-1624602573928)(E:\Typora\QQ截图20210624195441.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-42i3052A-1624602573929)(E:\Typora\QQ截图20210624210753.png)]

put方法

public synchronized V put(K key, V value) {// Make sure the value is not nullif (value == null) {throw new NullPointerException();}// Makes sure the key is not already in the hashtable.Entry<?,?> tab[] = table;int hash = key.hashCode();int index = (hash & 0x7FFFFFFF) % tab.length;@SuppressWarnings("unchecked")Entry<K,V> entry = (Entry<K,V>)tab[index];for(; entry != null ; entry = entry.next) {if ((entry.hash == hash) && entry.key.equals(key)) {V old = entry.value;entry.value = value;return old;}}addEntry(hash, key, value, index);return null;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RPsUlnAn-1624602573930)(E:\Typora\QQ截图20210624210912-1624542680568.png)]

扩容机制

private void addEntry(int hash, K key, V value, int index) {modCount++;Entry<?,?> tab[] = table;if (count >= threshold) {// Rehash the table if the threshold is exceededrehash();tab = table;hash = key.hashCode();index = (hash & 0x7FFFFFFF) % tab.length;}// Creates the new entry.@SuppressWarnings("unchecked")Entry<K,V> e = (Entry<K,V>) tab[index];tab[index] = new Entry<>(hash, key, value, e);count++;
}

Treeset源码解读

public class TreeSetSource {public static void main(String[] args) {//TreeSet treeSet = new TreeSetTreeSet treeSet = new TreeSet(new Comparator(){@Overridepublic int compare(Object o1, Object o2) {//下面调用String的compareTO方法进行字符串大小的比较return ((String) o1).compareTo((String) o2);}});treeSet.add("jack");treeSet.add("tom");treeSet.add("sp");treeSet.add("a");}
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Nj0G4mZj-1624602573930)(E:\Typora\QQ截图20210624220350.png)]

public TreeMap(Comparator<? super K> comparator) {this.comparator = comparator;
}
public TreeSet(Comparator<? super E> comparator) {this(new TreeMap<>(comparator));}

构造器把传入的比较器对象赋给了TreeSet的底层的 TreeMap的属性this.comparator

treeSet底层是treeMap

public V put(K key, V value) {Entry<K,V> t = root;//该树的根节点if (t == null) {compare(key, key); // type (and possibly null) check,检测是否为空root = new Entry<>(key, value, null);size = 1;modCount++;return null;}int cmp;Entry<K,V> parent;// split comparator and comparable pathsComparator<? super K> cpr = comparator;//cpr就是我们的匿名内部类(对象)if (cpr != null) {do {//一直循环直到找到插入位置parent = t;cmp = cpr.compare(key, t.key);//动态绑定到我们的匿名内部类compare,cmp是在比较规则的情况下之间的差值,比如字符串ascii码之间的差值if (cmp < 0)t = t.left;//在根节点的左边else if (cmp > 0)t = t.right;else//如果相等,即返回0,这个key就没有加入return t.setValue(value);} while (t != null);//t为空退出,找到了要插入的位置}else {//构造器为空,分析和上面一样if (key == null)throw new NullPointerException();@SuppressWarnings("unchecked")Comparable<? super K> k = (Comparable<? super K>) key;do {  parent = t;cmp = k.compareTo(t.key);if (cmp < 0)t = t.left;else if (cmp > 0)t = t.right;elsereturn t.setValue(value);} while (t != null);}Entry<K,V> e = new Entry<>(key, value, parent);//要插入的位置在parent的左边或者右边if (cmp < 0)parent.left = e;elseparent.right = e;fixAfterInsertion(e);size++;modCount++;return null;}

2021-06-25相关推荐

  1. 2021.06.06家庭财经系统制作(2)

    show tables; 查看数据库里有什么表命令. 碰到mysql软件问题.比想象的难缠. 用之前的方式打不开黑框(鼠标单击 mysql5.7 ccommand line Client),黑框一闪而 ...

  2. dataGridView右键菜单并选中该行 http://blog.csdn.net/lanmao100/archive/2009/06/25/4298529.aspx...

    dataGridView右键菜单并选中该行 程序代码: private void dataGridView1_CellMouseDown(object sender, DataGridViewCell ...

  3. 基于python的科技论文_实地科研 | 上海财经大学 | 金融科技、商业分析、人工智能:机器学习、人工智能及其在金融科技中的应用(2021.1.25开课)...

      课题名称   = 机器学习.人工智能及其在金融科技中的应用 =  项目背景   随着云时代的到来,机器学习.人工智能.大数据技术具有越来越重要的战略意义,并逐渐渗透到每一个行业和业务职能领域,成为 ...

  4. 读论文——Pre-Training with Whole Word Masking for Chinese BERT(2021 11.25)

    第一遍 标题以及作者(2021 11.25) 摘要 本文基于BERT,在RoBERTa上进行一系列改进,提出了用于中文的预训练模型MacBERT. 提出了一种新的掩码策略,MLM as correct ...

  5. Diabetes 糖尿病及其并发症.|2021/1/25(未完待续)

    目录 前言: 正文: ①宏观严重性: ②普遍状况:" 三多一少": ③定义 : ③胰岛素(Insulin,一种激素(harmone)) ④引出糖尿病病理: 1> 1-型糖尿病 ...

  6. 【2021.12.25】ctf逆向中常见加密算法和编码识别

    [2021.12.25]ctf逆向中常见加密算法和编码识别(含exe及wp) 文章目录 [2021.12.25]ctf逆向中常见加密算法和编码识别(含exe及wp) 0.前言 1.基础加密手法 2.b ...

  7. vue+element 实现试卷答题功能,单选题 ,多选题,判断题,简答题(2.0版本,2021.3.25更新)

    vue+element 实现 试卷答题功能,单选题 ,多选题,判断题,简答题(2.0版本,2021.3.25更新) 文章目录 vue+element 实现 试卷答题功能,单选题 ,多选题,判断题,简答 ...

  8. 2021.06.03邮票面值设计

    2021.06.03邮票面值设计 题目描述 给定一个信封,最多只允许粘贴 N 张邮票,计算在给定 K(N+K≤15)种邮票的情况下(假定所有的邮票数量都足够),如何设计邮票的面值,能得到最大值 MAX ...

  9. 2021.2.25课程摘要(逻辑教育-王劲胜)

    2021.2.25课程摘要 逻辑教育-13期-Python基础班-王劲胜 一.面向对象(中) 二.面向对象(下) 逻辑教育-13期-Python基础班-王劲胜 一.面向对象(中) ☆property装 ...

  10. 公众号内容拓展学习笔记(2021.3.25)

    公众号内容拓展学习笔记(2021.3.25)

最新文章

  1. 全球及中国手机便携式移动电源行业营销模式及投资竞争力分析报告2021-2027年版
  2. MERGE语句——数据集横向合并
  3. Java黑皮书课后题第5章:*5.1(统计正数和负数的个数然后计算这些数的平均值)编写程序,读入未指定个数的整数,判断读入的正数有多少个、负数有多少个,然后计算输入值的总和和平均值(不记0,浮点表示)
  4. 生成n套数位加减乘除_leetcode 算法汇总(四)位运算
  5. python高频词_python几万条微博高频词分析
  6. PHP中使用八进制 可以在前面加,PHP学习笔记(二)
  7. ElasticSearch是否有架构?
  8. MQ中将消息发送至远程队列的配置
  9. 一些你可能不知道的 Python 小技巧!
  10. ClickHouse在字节跳动推荐和广告业务部门的最佳实践
  11. 主成分与因子分析异同_主成分分析和因子分析有什么区别?
  12. 数据分析案例-大数据相关招聘岗位可视化分析
  13. 什么是泛域名?如何做泛域名解析?
  14. mybatis 源码系列(四) 数据库驱动Driver加载方式
  15. python安装requirement.txt
  16. ios系统脚本服务器加速,让iOS系统加速飞起来 speed intensifier插件让iOS系统加速
  17. JAVA 调用地图API
  18. 知识抽取学习笔记:面向非结构化数据的抽取
  19. 基于Autojs的66联盟快手版辅助
  20. 微型计算机的多级存储结构,微型计算机存储系统结构.doc

热门文章

  1. 紫光同创 FPGA 开发跳坑指南(五)—— DDR3 控制器 IP 的仿真
  2. android汤姆猫的实验报告,毕业设计(论文)-基于Android的会说话的汤姆猫的设计与实现.doc...
  3. 手机语言 Symbian 术语表
  4. python bi_这5款BI工具,Python工程师最爱用
  5. Yapi接口平台个人总结
  6. 《暗通道优先的图像去雾算法》读书笔记
  7. bios error 装系统acpi_重装系统遇到bios acpi错误。
  8. pdf加密文件怎么解密?
  9. php phpunit selenium,PHPUnit和Selenium
  10. r语言是高级编程语言_R编程语言介绍