java集合派系学习

一、collection派系

1.1 set 无重复

treeset有序set,底层是treemap,插入数据存在map的key位置,value是固定值。

hashset底层是hashmap,同样插入数据存在map的key位置,value是固定值。

 

1.2 list 可重复

arrayList的类图如下:

底层结构,capacity默认长度,默认10

添加:elementData()存储具体的元素,他的默认无参构造函数是懒初始化的,在add时才初始化,在add时首先元素增长1然后判断elementData空间是否够,够了直接存放,不够就扩容(扩容完对数组进行复制拷贝,从而完成初始化),每次扩容变成原来的1.5倍长。

查找:先检查数组越界,数组的下标直接访问

删除:删除后,后续所有节点会全部移动位置,首先计算要移动的数量,做数组的拷贝,然后将最后一个数组元素置为null,由gc回收。

modcount:其实就是版本记录器,当多线程并发访问同一个list时,版本不一致的话直接失败。

LinkList

deque双端队列

属性:Node first 头节点;Node last尾节点;size大小;其中Node是内部类

增:add()尾部直接插入元素,add(index):首先使用二分找到index对应的node直接在该位置插入即可。

删:remove()删除头,remove(index);

查:get(index):先检查越界,然后通过判断index和size/2的大小比较,小则从头遍历,否则从尾遍历。

 

集合多线程安全

vector线程安全的。底层原理和arraylist差不多,动态扩容等

在add()方法上加了一个synchronized,同理remove方法上也加了这个锁。

第一种就是加锁,第二种工具类,Collections.synchronizedList(),可以将list转为一个多线程安全的SynchronizedList;

SynchronizedList的增删都加了锁,所以线程安全的。

 

二、map派系

2.1 HashMap

属性:size,Node内部类,entrySet,modcount版本号,TREEIFY_THRESHOLD=8即当连表个数大于8时转为红黑树,红黑树不足8时转化为链表,DEFAULT_LOAD_FACTOR=0.75计算因子,。

增:一搬分两个阶段,1先找到插入位置,然后在连表或红黑树上插入;

第一阶段:(用key的hashcode与数组长度取模运算得到具体位置),其实hashmap并不是与数组长度取余,而是用key的hashcode与数组长度-1的值做与运算。所以数组的长度必须是2的n次幂。

put(K,V):resize双倍扩容或第一次的初始化操作。首先用一阶段找到位置,若位置无值直接创建node存放即可,若果有值且是连表直接在连表尾部插入,如果是红黑树则需要红黑树的插入。

查:get(Key):首先根据key的hashcode确定数组位置,然后根据数组位置,直接返回数组值或继续查找连表或继续查找红黑树。

动态扩容:

1,什么时候扩容?当++size()>数组长度*平衡因子,则创建比old array两倍大的新数组,并重新计算位置将老的数据复制过去。扩容后元素的位置,要么还是在原来位置,要么是在原来位置+oldArray.length,如,index=17;oldArray=16,newArray=31,所以在oldArray的1位置,到新数组后变成了17位置。即index&oldArray.length==0(最高位是不是1来判断),位置不变,否者位置变为加oldArray.length后的位置,所以一个连表可能变成两个连表。

hash与int的最大值,然后和数组长度取模。而hashmap是与数组长度-1的值,hashtable基本不用了。

 

TreeMap底层是红黑树,为什么不使用AVL平衡二叉树呢,查询效率更高,是因为数据插入10次(1到10),AVL调整6次,而红黑树调整5次。再做增删调整树会浪费很大的性能,所以选择了红黑树。

属性:Comparator默认自然排序比较器;Entry<K,V> root树的根节点,Entry就是红黑树节点有key,value,left,right,parent,以及isRed;size个数,modcount版本号;

put(K,V):先比较当前节点的key和插入的key用比较器比较;用比较器采用递归的二分查找,找到位置插入。

get(K): 用比较器二分查找。

 

三、两大派系关系如下,相辅相成

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章