Java 源码
集合接口Set、List、Map。
Set:元素不能重复, 通过equals确保对象唯一性。(TreeSet、HashSet、LinkedHashSet)。
List:元素可以重复,有序链入。(ArrayList、Vector、LinkedArrayList).
Map:从键映射到值的过程。(HashMap、TreeMap、LinkedHashMap)
Future(异步计算模型的返回结果)
get()返回结果,cacel()在任务完成前取消、isCanceled取消计算、isDone()任务是否完成。
ArrayList(动态数组实现)
不安全、允许空、查询修改操作比较方便。
默认容量是10,扩容原来的1.5倍。
扩容机制:把原来的数组复制到另一个内存空间更大的数组中、把新元素添加到扩容以后的数组中。扩容方法是add(某种类型 某种类型参数)。先增加长度,然后将添加元素到数组。增加元素的时候在尾部。
CopyOnWriteArrayList
比Vector好在,读时不加锁(ReentrantLock)。
数组内用transient、volatile修饰。
支持读多写少的并发情况。
Vector(动态数组实现)
线程安全(Sychronized,加载Vector的public方法中)
扩容机制(通过判断增长系数来扩容,增长系数大于0 则扩容),默认容量是10,扩容原来的2倍。
ArrayList 和LinkedList插入(O(1)、O(n))删除时间复杂度(O(n)、O(n))。
HashMap(数组+链表+1.8之后引用红黑树)
1 为什么使用红黑树
HashMap采用了数组和链表的数据结构,它存储的内容是键值对(key-value)映射。在JDK1.8版本后,java对HashMap做了改进,在链表长度大于8的时候,将后面的数据存在红黑树中。红黑树虽然本质上是一棵二叉查找树,但它在二叉查找树的基础上增加了着色和相关的性质使得红黑树相对平衡,从而保证了红黑树的查找、插入、删除的时间复杂度最坏为O(logn)。加快检索速率。红黑树占用空间是链表两位。
2 数组和链表分别的作用
数组中存放的是对象,数组部分进行的操作主要是散列。根据hash算法实现快速存储第一步,确定存储在数组的哪个位置。每一个单位中存储的内容为:key+value+指针,其中指针主要用来进行链表操作。链表存在主要是为了解决经过hash计算后会有重复值这一问题。当多次散列后,hash计算结果值一致,需要存放在数组的同一部分,就要使用链表结构。当一个非空数组中需要存入新的对象,就需要把原来对象中末尾的指针指向新的对象,每次有新的对象key值经过hash计算后得到相同的值,都会重复以上步骤,“往下塞”,使每个对象都能够被访问到。
3 HashMap判断key相同
if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))先判断hash是否一致,然后再判断传入key和当前集合中是否有相同的key。如果key相同,则新值替换旧值。其中在判断中使用了==和equals。
4 HashMap扩容以及元素的移动
HashMap默认的负载因子大小为0.75,当一个map填满了75%数组的时候,和其它集合类(如ArrayList等)一样,将会创建原来HashMap大小16的两倍的数组,来重新调整map的大小,并将原来的对象放入新的数组中。假设扩容前的map大小为2的N次方,扩容后map中的元素只有两种情况:元素hash值第N+1位为0:不需要进行位置调整。元素hash值第N+1位为1:调整至原索引的两倍位置。
5 HashMap的hash冲突解决办法
hash冲突:如果存在相同的hashCode值,那么它们索引位置相同。如果此时key不相同,就产生hash冲突。
开放定址法:通过一个探测算法,当某一个槽位已经被占据的情况下,继续查找下一个可以使用槽位。
链地址法:将所有hash为i的元素构成一个称为同义词链的单链表,并将单链表头指针存在哈希表的第i个单元中。
6 为什么不用二叉查找树
选择红黑树是为了解决二叉查找树的缺陷,二叉查找树在特殊情况下会变成一条线性结构(跟原来链表结构一样会造成很深的问题),遍历查找会非常慢。而红黑树在插入新数据后可以通过左旋,右旋、变色这些操作来保持平衡,引入红黑树就是为了使查找数据更快,解决链表查询深度的问题。红黑树属于自平衡的二叉查找树,虽然为了保持“平衡”是需要付出代价,但是该代价所损耗的资源要比遍历线性链表少很多。
7 默认容量16、装载因子0.75.
map 用hash&(length-1)
转线程安全可用Collections.sychronizedMap(new HashMap)。
LinkedHashMap
有一个双向链表维护输入顺序。
默认容量16,装载因子0.75
CurrentHashMap(Segment)
支持并发、安全。16个Segment构成,继承ReentrantLock加锁。
1.8之后引用红黑树。
默认容量16,装载因子0.75
HashSet
不允许重复,允许空,存储顺序和输入顺序不一定相同。
容量默认16,装载因子0.75.
LinkedHashSet
加了一个双向链表,剩下和HashSet相同。
HashTable(数组或者链表)
线程安全,键值均不允许为空
需要高并发可用
默认容量11,装载因子0.75
扩容时2n+1