关于Java集合的部分复习知识点整理
ArrayList
- ArrayList本质上继承了AbstractList,而AbstractList则是继承了Collection集合类,而且Arraylist是实现了List的接口
- ArrayList初始的容量,DEFAULT_CAPACITY = 10,即初始容量为10,但初始化对象的时候能够传入你自定义的容量最大容量为Interger.MaxValue-8
- ArrayList的默认元素存储,是一个Object[]数组
- ArrayList源码里面存在一个ensureCapacity的方法,用来确认数组的容量是否须要扩容,扩容的时候采用的是Arrays.Copyof的方法,复制元素到一个新的数组
- 关于ArrayList的扩容机制,达到了定义容量(不传入容量的话,即为默认容量)的时候,会动态扩容1.5倍,也是采用上述的复制方法
- ArrayList实际上是存在手动缩容的方法的,在源码中有叫作 trimToSize()的方法,通常是手动调用的
- ArrayList中删除元素的Remove方法其实也是采用arraycopy()的方法来进行元素的移动,本质跟数组差很少
- ArrayList是线程不安全的,里面没有实现线程安全的保障,多线程在访问的时候,实现的自动扩容也是形成线程不安全的一部分缘由。相反,常见的Vector基本上是靠synchronized来实现线程安全的
HashMap
- HashMap实现了Map接口,初始容量为16,最大容量为1 << 30,默认加载因子为0.75,若是本身传入初始值K,则容量为大于K的2次方整数,例如:传入10的话,则容量为16

- HashMap的插入原理

在JDK1.8以前,HashMap使用数组+链表实现,即便用链表处理冲突,同一hash值的节点都存储在一个链表里。可是当位于一个桶中的元素较多,即hash值相等的元素较多时,经过key值依次查找的效率较低。而JDK1.8中,HashMap采用数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减小了查找时间,红黑树转链表的阈值是6数组
- hash函数是经过拿到key的hashcode,而后让hashcode的高16位和低16位进行异或操做,这样设计的缘由是尽量地减少hash碰撞,其二是位运算比较高效
hashmap若是采用头插法的话,在多线程的状况下会产生环,而且hashmap在多线程下也是不安全的,在JDK8以前的话,是先判断扩容再插入的,而JDK8以后则是先插入再判断是否须要扩容,扩容为扩容到原数组大小的2倍安全
- 扩容的时候1.7须要对原数组中的元素进行从新hash定位在新数组的位置,1.8采用更简单的判断逻辑,位置不变或索引+旧容量大小
- 链表转红黑树,并非达到8个Node节点的阈值就进行转换,而是要判断一下整个数据结构中的Node数量是否大于64,大于才会转,小于就会用扩容数组的方式代替红黑树的转换
扩展
Java中有HashTable、Collections.synchronizedMap、以及ConcurrentHashMap能够实现线程安全的Map。数据结构
- HashTable是直接在操做方法上加synchronized关键字,锁住整个数组,粒度比较大;
- Collections.synchronizedMap是使用Collections集合工具的内部类,经过传入Map封装出一个SynchronizedMap对象,内部定义了一个对象锁,方法内经过对象锁实现;
- ConcurrentHashMap使用分段锁,下降了锁粒度,让并发度大大提升。