ArrayList ,LinkedList , HashSet ,HashMap , HashTable , LinkedHashMap , TreeMap , ConcurrentHashMap
ArrayList
存储结构 :
数组保存对应的数据
存储增长 :
理应添加当前大小 + 1/2当前长度,如果实际需要增长的长度更大,那就用实际增长的长度,否则用前面的理应长度
LinkedList
存储结构 :
节点存储 , next
存储增长 :
没有这种判断,一个个节点的顺序下去
HashSet
存储结构 :
依赖于HashMap
HashMap(Fail Fast Iterator)
基本:
HashMap可以保存null,保存在table为0的下标
遍历的时候,不能对,对应的迭代器操作(add,remove,update)
存储结构:
Entry数组保存,每个Entry都可以有next节点
存储增长:
在需要新增长度的时候,按照原来的长度的两倍增长
保存过程:
put进去的时候,会先indexFor 获取对应的index。
然后,通过这个下标,不断迭代next,获取对应的entry,如果两个key相等的话,就会覆盖。
然后,准备添加entry。如果对应index的数组有值并且当前的HashMap的长度(有值的Entry个数)大于一定的长度(HashMap设置的容量 * 比例因子(0.75))
那么就会将新的长度设成原来的长度的2倍,并且将原来的table的entry,都重新计算一次hash(包括next的也会重新计算),放到新的table内,
重新算一次现在这个新增的entry的hash,从而重新计算index。
最后新增entry,如果新的index还是有节点的话,当前新增节点作为next节点。否定,就是对应的index节点。
hash函数:
如果key是string,则用string的hashcode方法。否则,用他们自定义的hash方法
h = hashSeed
h ^= hashCode
然后,h ^= (h >>> 20) ^ (h>>>12)
最后 ,h ^ ( h >>> 7 ) ^ (h >>> 4)
上述的方法就是为了将这些hash值打算。
因为,这些hashCode是int,在值比较相近的时候,他们在低位有很多相同的地方,
为了将这个地方打散就用了上述方法打散低位的数值。
indexFor函数:
通过hash函数,拿到一个被打散的hash值(这样的hash值,在数值相邻的时候,hash值也大不一样)
然后将这个hash 与 table.length - 1 。 这里为什么不是hash % table.length 呢?
因为,hashMap的存储长度,初始长度是16,是按照2的倍数增长。所以,table.length - 1 对应的所有低位都是1。
最后,会发现 hash % table.length == hash & (table.length - 1)
HashTable(多线程强一致性)
与HashMap的实现都是一样,只是每个方法都是synchronized(调用这个方法的对象作为锁)
不可保存null
LinkedHashMap
重写了createEntry和addEntry等方法
在HashMap的基础上,额外新增了一个链表节点存储,保证插入有序
TreeMap
每次put的时候,都会做一次比较,比较后,再决定插入左边还是右边的节点
存储结构是红黑树,TreeMap保证值有序
ConcurrentHashMap(Fail Safe Iterator,多线程弱一致性)
基本 : 遍历的时候,可以对元素操作,因为遍历的时候,是对副本做操作。
存储 : 使用Segment保存,通过分段的方法,将大量的数据分到多个segment。
segment,内部再通过一些关键字(volatile),锁机制,去保存数据
比较 :相较于HashTable,ConcurrentHashMap,通过segment以及关键字,将锁的时间,减少了很多
因为 HashTable 迭代的时候,会比较久,占用的时间比较久。HashTable 在 量比较大的时候,会很慢。
弱一致性 : 无法保证,同时删除以及写入的时候,是否会出现写入的内容被删除。因为,clear是for循环将所有的segment,clear。并没有加锁。
Update At 2017-12-04 21:51:00