自己坐车的时候没事便回顾一些Java基础的东西,想到集合框架的时候闲着无聊便掏出手机把自己理解的常见的集合框架给打了出来,大家可以一起交流交流哈。
1.ArrayList:
ArrayLIst是List接口的一个可变大小的数组的实现,它的内部使用的是一个Object对象数组来存储元素的。初始化ArrayList的时候,可以指定初始化容量的大小,如果不指定,添加第一个元素的时候,数组会扩容为10,这也是它的默认大小。然后就是扩容问题,每添加一个新的元素,ArrayList都会调用ensureExplicitCapacity方法判断是否需要扩容,要是需要的话就调用grow方法扩容1.5倍,在JDK1.6及之前采用的还只是数字运算扩容就是*3/2+1的形式,之后就是位运算右移的方式了。然后就是ArrayList的删除,它会先检查删除对象的下标是不是在范围内,是的话就调用System.arrayCopy方法把右边的数组向左移动,并且将size减一,然后只为null。ArrayList差不多就是这样了。
2.LinkedList:
LinkedList实现了List和Deque接口,是一种链式类型的数据结构,支持高效的插入和删除操作,因为实现了Deque接口,使得LinkedList类也具有队列的特性,它的底层实现的数据结构是一个双端的链表。
3.HashSet:
HashSet内部是使用HashMap来存储对象的,所以它的很多的特性都是结合HashMap来的,比如添加元素操作就是向map中添加键值对(e,Object),添加的元素e就是map中的key值,所以它是唯一的,而Object在HashSet源代码中是PRESENT,它是一个静态类对象,所有的HashSet实例共享这个对象。然后就是HashSet没有get方法,获取元素要用到iterator()迭代器,因为HashSet的元素都被当成map的key来存储,而map中没有单独获取一个key的方法,但有获取所有Key的方法叫KeySet。
4.HashMap:
从结构实现来讲,HashMap就是数组+链表+红黑树的形式,其中红黑树是JDK1.8增加的,数组是哈希桶数组源码中用table表示。在内部HashMap默认的数组大小是16,采用的是Hash算法来确定哈希桶数组索引位置,hash算法大致分为三步:取key的hashCode值,高位与运算和取模运算,h ^ (h >>> 16)高位与运算 h & (length-1)取模运算。
然后就是HashMap的Put方法:具体的过程我就不细说了,中间有几个主要的判断条件,像数组是否初始化,用hash算法得到的索引在哈希桶中是否为空,哈希桶中是链表还是红黑树,以及key是否存在等,其中判断key值用了hashCode和equals方法,链表长度大于8就会转换成红黑树。
Put总会使元素达到最大容量,所以HashMap的扩容机制也非常的重要,扩容的时候,调用split函数对树进行拆分,使用两个单链表,如果单链表的元素个数小于等于6个,那么相应位置的数组就变成了链表,否则就树化。元素进入两个链表的依据是hash算法, 如果相应的bit为1就进入一位链表,否则就进入另外一个链表,然后就是扩容时一个元素的下标要么在原位置,要么在index+oldCapacity位置。
至于ConcurrentHashMap,HashTable我会在写并发系列的时候加上。