java Collection接口和Map接口知识点总结

版权声明:本文为博主原创文章,请尊重劳动成果,转载注明一下出处。 https://blog.csdn.net/zq1994520/article/details/81431529

        最近写代码,感觉对jdk中Collection和Map中的实现方式和原理有些遗忘,为了在写代码的时候让代码更加简介和让性能更加优秀,所以我先必须了解其中容器增长方式和原理,HashMap,如果每个Node桶存放的数据大小大于等于8,就会采用红黑树存储。

工具:starUML、IDEA

jdk版本:jdk1.8.0_102

(一)  先贴上一张类图:

辛苦制作的UML类图

(二) 其中Collection和Map部分实现中实现参数。

1、 全局实现的参数:

新容量大小/原容器大小 = N/O

 x = 没有该值

(一)
  Collection
  List Set
  ArrayList AttributeList RoleList LinkedList Vector Stack HashSet TreeSet LinkedHashSet
实现方式

Object[]

数组

Object[]

数组

Object[]

数组

Node<E>

双向链表

Object[]

数组

Object[]

数组

HashMap<E,Object>

NavigableMap<E, Object> HashMap<E,Object>
默认容器大小 10 10 10 x 10 10 16 x 16
扩充容量方式 System.arraycopy System.arraycopy System.arraycopy x System.arraycopy System.arraycopy (Node<K, V>[])new Node[newCap] x (Node<K, V>[])new Node[newCap]
N/O 1.5 1.5 1.5 x 2(默认,值在初始化的第二个参数可设置) 2默认,值在初始化的第二个参数可设置) 2 x 2
负载因子 1 1 1 x 1 1 0.75f x 0.75f
默认门阀 记载因子*容量大小 记载因子*容量大小 记载因子*容量大小 x 记载因子*容量大小 记载因子*容量大小

如果使用无参构造方式,默认门阀为“默认加载因子”*"默认cap大小".

如果使用其他构造函数,门阀值初始为

将该初始因子-1的值写成机器码,从最高位(从左往右除符号位的第一个1)开始,右边所有位变1的值。

x

如果使用无参构造方式,默认门阀为“默认加载因子”*"默认cap大小".

如果使用其他构造函数,门阀值初始为

将该初始因子-1的值写成机器码,从最高位(从左往右除符号位的第一个1)开始,右边所有位变1的值。

线程安全 x
(二)
  Map
   
  HashMap LinkedHashMap Hashtable WeakHashMap TreeMap EnumMap Attributes ConcurrentHashMap Properties
实现方式

Node<K, V>[]

(根据key的hash值和长度来决定选择那个桶index)有hashValue,next的链表结构(这里面定义了TreeNode extend LinkedHashMap.Entry)

LinkedHashMap.Entry<K, V> 双向链表实体,继承HashMap.Node<K, V>

Entry<K,V>[]

是HashMap的安全实现

Entry<K,V>[]

是继承WeakReference实现弱引用,减少在内存中存活时间,节省内存。

Entry<K, V>

有right,left,parent的map结构

Object []

数组

Map<Object, Object>,使用的HashMap实现

Node<K,V>[]

数组

Entry<K,V>[]

是HashMap的安全实现,是继承于HashTable

默认容器大小 16 x 11 16 x 动态 11 16 11
扩充容量方式 (Node<K, V>[])new Node[newCap] x new Entry<?, ?>[newCapacity] (Node<K, V>[])new Node<?, ?>[newCap] x x (Node<K, V>[])new Node[newCap] (Node<K, V>[])new Node<?, ?>[n << 1] new Entry<?, ?>[n]
N/O 2 x 2  另外加1 2 x x 2 x 2 另外加1
负载因子 0.75f x 0.75f 0.75f x x 0.75f x 0.75f
默认门阀

如果使用无参构造方式,默认门阀为“默认加载因子”*"默认cap大小".

如果使用其他构造函数,门阀值初始为

将该初始因子-1的值写成机器码,从最高位(从左往右除符号位的第一个1)开始,右边所有位变1的值。

x 记载因子*容量大小 记载因子*容量大小 x x

如果使用其他构造函数,门阀值初始为

将该初始因子-1的值写成机器码,从最高位(从左往右除符号位的第一个1)开始,右边所有位变1的值。

x

记载因子*容量大小
线程安全

2、线程安全构造函数和门阀与N/O的关系详细说明: 

新容量大小/原容器大小 = N/O

新门阀/老门阀 = NT/OT

 x = 不存在

  i = 输入值

oldCap = 老容器大小

oldCap/2(取整) = oldCap >> 1 

{2^n}=  满足2的n次方值大于i条件2的n次方的最小值

动态 = 表示它没有实现,需要传入一个实现的对象,按照对象来使用

1) 线程安全:

线程安全(一)
  Vector Stack(继承与Vector)
  初始容量 负载因子 门阀 N/O NT/OT 初始容量 负载因子 门阀 N/O NT/OT
默认容器大小 10 x x 2 x 10 x x 2 x
只有initialCapacity参数值 i x x 2 x x x x x x
有initialCapacity,loadFactor参数的值 i x x 这儿没有loadFactor参数,有capacityIncrement参数,每次增加capacityIncrement x x x x x x
线程安全(二)
  Stack(继承与Vector) Hashtable ConcurrentHashMap Properties
  NT/OT 初始容量 负载因子 门阀 N/O NT/OT 初始容量 负载因子 门阀 N/O NT/OT 初始容量 负载因子 门阀 N/O NT/OT
默认容器大小 x 11 0.75f 8 2 倍另外单独+1 2 16 x x 1.5倍另外单独 + 1 x 11 0.75f 8 2 倍另外单独+1 2
只有initialCapacity参数值 x i 0.75f

i

* 0.75f

2 倍另外单独+1 2 3i/2 + 1   x 1.5倍另外单独 + 1 x i 0.75f

i

* 0.75f

2 倍另外单独+1 2
有initialCapacity,loadFactor参数的值 x i i i(容量) *i(负载因子) 2 倍另外单独+1 2 {2^i/loadFactor} x x 1.5倍另外单独 + 1 x i i i(容量) *i(负载因子) 2 倍另外单独+1 2

2)线程不安全:

线程不安全(一)
  ArrayList AttributeList RoleList LinkedList
  初始容量 负载因子 门阀 N/O NT/OT 初始容量 负载因子 门阀 N/O NT/OT 初始容量 负载因子 门阀 N/O NT/OT 初始容量 负载因子 门阀 N/O NT/OT
无参构造函数容器大小 10 x oldCap 1.5 x 10 x oldCap 1.5 x 10 x oldCap 1.5 x x x x x x
只有initialCapacity参数值 i x oldCap 1.5 x i x oldCap 1.5 x i x oldCap 1.5 x x x x x x
有initialCapacity,loadFactor参数的值 i x oldCap 1.5 x i x oldCap 1.5 x i x oldCap 1.5 x x x x x x
线程不安全(二)
  HashSet(数据保存是通过HashMap实现的) TreeSet LinkedHashSet(继承HashSet) HashMap
  初始容量 负载因子 门阀 N/O NT/OT 初始容量 负载因子 门阀 N/O NT/OT 初始容量 负载因子 门阀 N/O NT/OT 初始容量 负载因子 门阀 N/O NT/OT
无参构造函数容器大小 16 0.75f 12 2 2 x x x x x 16 0.75f 12 2 2 16 0.75f 12 2 2
只有initialCapacity参数值 {2^n} 0.75f

{2^n}

* 0.75f

2 2 x x x x x {2^n} 0.75f

{2^n}

* 0.75f

2 2 {2^n} 0.75f

{2^n}

* 0.75f

2 2
有initialCapacity,loadFactor参数的值 {2^n} i

{2^n}

* 0.75f

2 2 x x x x x {2^n} i

{2^n}

* 0.75f

2 2 {2^n} i

{2^n}

* 0.75f

2 2
线程不安全(三)
LinkedHashMap WeakHashMap TreeMap EnumMap Attributes(数据用HashMap来保存)
初始容量 负载因子 门阀 N/O NT/OT 初始容量 负载因子 门阀 N/O NT/OT 初始容量 负载因子 门阀 N/O NT/OT 初始容量 负载因子 门阀 N/O NT/OT 初始容量 负载因子 门阀 N/O NT/OT
16 0.75f 12 2 2 16 0.75f 12 2 2 x x x x x 动态 动态 动态 动态 动态 16 0.75f

{2^n}

* 0.75f

2 2
i 0.75f

{2^n}

* 0.75f

2 2 {2^n} 0.75f

{2^n}

* 0.75f

2 2 x x x x x 动态 动态 动态 动态 动态 {2^n} 0.75f

{2^n}

* 0.75f

2 2
i i

{2^n}

* 0.75f

2 2 {2^n} i

{2^n}

* 0.75f

2 2 x x x x x 动态 动态 动态 动态 动态 x x x x

 补充描述:这里面有些很复杂,详细还是得去研究源码,而且,每个jdk版本的实现的方式不一样,建议有时间详细看源码,了解其中原理。最重要的是HashMap,TreeMap,Hashtable,ConcurrentHashMap这些详细查看很有用, 这个其中还常使用到CAS。

(三) 知识点总结:

HashMap,虽然存储数据是通过key-value的形式存储的,但是,它内部为了提高查询效率,使用的key的hash值,构建数组对象链。先是数组,称作“桶”,通过hash值来判断放那个桶,桶的数量就是上面的cap。每个桶存放的数据小于8个的时候,是采用简单的对象表,如果每个Node桶存放的数据大小大于等于8,针对该桶的数据就会采用红黑树存储。

ConcurrentHashMap在这个版本实现和HashMap内容差不多,只是增加了线程安全的操作,其中加载因子只是在容器初始化的时候和cap通过cap/loadFactor + 1向上取2^n的整数,还有这个版本Segment只有在JAVA对象流进行序列化和反序列化中使用。

猜你喜欢

转载自blog.csdn.net/zq1994520/article/details/81431529