1.单列集合
单例集合分为list集合和set集合,list集合是有序集合,其常用实现类为LinkedList,ArrayList,Vectory,set集合是无序集合,其常用实现类为HashSet,TreeSet。
2.Iterator与Iterable
Collecition接口继承了Iterator接口,在Iterator接口中有一个抽象方法,返回了Iterator(迭代器)对象,通过查看源码,可以发现Iterator中有四个方法,其中hasNext()和next()组成了迭代器遍历的功能,增强for循环(for each)的底层原理就是迭代器循环
3.List
因为底层是数组和链表,所以存在索引。
3.1ArrayList
ArrayList可以存放任意元素,包括null,因为ArrayList的方法没有用sychronized锁修饰,所以是线程不安全的。
ArrayList会维护一个Object[] elementData的数组。
ArrayList有三种构造方法,int类型参数构造,无参构造和Collection集合参数构造,当使用无参构造的方法创建对象时,会给ArrayList指定一个默认空数组,当给ArrayList对象赋值的时候,会先将对象装箱,然后判断容量是否够用,当容量不够用的时候,会用Arrays.copyOf方法扩容,首次赋予默认最小容量10,当容量需要扩容时,以1.5倍的大小扩容。
3.2Vectory
线程安全,双倍扩容。
3.3LinkedList
实现了双向链表和双端队列
因为LinkedList的底层是双向链表,所以当业务场景是增删的时候效率更高。
3.4集合的选择
单线程用ArrayList和LinkedList,都是线程不安全,当改查业务场景多,偏向使用ArrayList,当增删业务场景多,偏向使用LinkedList。
4.Set
元素无序且不能重复,底层是数组+链表
4.1HashSet的源码解读
底层是HashMap
维护了是数组+单向链表
添加元素时,先计算hash值,会转换成索引值
找到存储表table,看索引位置是否有值,没有则直接加入,有则进行equals比较(自定义)||key的==比较,不相同则放入链表last
HashSet通过HashMap的putVal方法去存值
if ((tab = table) == null || (n = tab.length) == 0)//先将hashMap中的table值赋值给辅助变量tab
n = (tab = resize()).length;//重设tab的大小,默认值是1 << 4
一开始给HashSet数组(table)赋值16,临界值默认为0.75*16,当size大小达到临界值,则扩容为16*2,以此类推。
HashSet的扩容机制:在java8中,链表元素大于等于8,且table的大小等于64,会将链表进行树化,若table大小没有到64,则会先扩容,并仍然采用数组的扩容机制
4.2LinkedHashSet
继承了HashSet
底层是LinkedHashMap,继承了HashMap
维护了数组+双向链表,使得数据的插入变得有序
4.3TreeSet
底层是TreeHash
5.双列集合(Map)
Map与Collection并列存在,用于存储具有映射关系的的数据:Key-Value
Map中的Key和Value可以存储任意引用类型的数据,会封装到HashMap$Node对象中
Map中的Key不能重复,因为先hash判断,再equals||key的==比较
HashMap中将K-V存放在Node对象中,因为为了便于遍历,向上转型为Entry,再存放到EntrySet对象中,因为Entry接口有getKey(),和getValue()的方法。
HashMap中,Key另外有一个keySet对象指向key数组,Value有另外一个Collection对象只想Value数组
5.1Hashtable
K-V都不能为null
默认table数组大小为11,临界值默认为0.75*11,自动扩容为2倍+1扩容
5.2TreeMap
使用有参构造器时,可以有序,比较规则为自定义匿名内部类
K-V都不能为null