文章目录

写在前面
-
下面先定一个规定:
O r d e r ( O 1 ) 表 示 有 序 , D i s o r d e r ( O 2 ) 表 示 无 序 Order(O1)表示有序,Disorder(O2)表示无序 Order(O1)表示有序,Disorder(O2)表示无序
T h r e a d − s a f e ( T 1 ) 表 示 线 程 安 全 , T h r e a d − u n s a f e ( T 2 ) 表 示 非 线 程 安 全 Thread-safe(T1)表示线程安全,Thread-unsafe(T2)表示非线程安全 Thread−safe(T1)表示线程安全,Thread−unsafe(T2)表示非线程安全
A l l o w a b l e − r e p e a t − v a l u e ( R 1 ) 表 示 允 许 重 复 值 , N o t − a l l o w a b l e − r e p e a t − v a l u e ( R 2 ) 表 示 不 允 许 重 复 值 Allowable-repeat-value(R1)表示允许重复值,Not-allowable-repeat-value(R2)表示不允许重复值 Allowable−repeat−value(R1)表示允许重复值,Not−allowable−repeat−value(R2)表示不允许重复值
-
什么叫有序,什么叫无序,集合类中存进去的顺序和取出来的顺序不一致即无序
-
Java 集合类中两个关键顶层父接口:1.Collection 2.Map,除了这两个接口外,还有诸如 3.Iterator 迭代器接口(主要做集合中数据迭代工作),4.Collections,5.Arrays 集合类的工具类(主要提供静态方法对集合元素排序搜索等线程安全操作),他们都在
java.util
包中- Collection 接口中两个关键子接口是:1.List 2.Set
- List 接口下有非常常用的 1.ArrayList(O1,T2,R1)2.LinkedList(O1,T2,R1)两个集合类
- Set 接口下有非常常用的 1.HashSet(O2,T2,R2)2.TreeSet(二叉树自动给它排了序,T2,R2)3.LinkedHashSet(O1 ,T2,R2) 三个集合类
- Map 接口中非常常用的 1.HashMap(O2,T2,R2)2.TreeMap(二叉树自动给它排了序,T2,R2)3.LinkedHashMap(O1 ,T2,R2)4.HashTable(O2,T1)四个集合类
- Iterator 迭代器接口,Collection 中可以产生 Iterator,Map 中可以产生 Collection,常用方法有
next()
获取序列中下一个元素,有hasNext()
检查序列中是否还有元素,remove()
将迭代器新返回的元素删除 - Collections 工具类是专门来对集合类进行骚操作的工具类
- Arrays 工具类是专门来对数组进行骚操作的工具类
- Collection 接口中两个关键子接口是:1.List 2.Set
1.List
- 有序列表
- 允许存放重复元素
1.1 ArrayList
- 有序
- 非线程安全
- 允许重复值
- 使用较多
- 数据结构:数组
- 使用场景:查询快,增删慢
- 扩容机制:初始大小为 10,
ArrayList.ensureCapacity(int minCapacity)
,超过长度的一倍即可开始扩容,容积取 int 型(oldCapacity * 3)/2 + 1
和minCapacity
最大的那个,也就是想当为 1.5 倍,然后用拷贝方式把以前数据存进新数组,minCapacity
比oldCapacity
小就不扩容
1.2 LinkedList
- 有序
- 非线程安全
- 允许重复值
- 使用较多
- 数据结构:双向链表
- 使用场景:查询慢,增删快
- **扩容机制:**由于底层采用双向链表实现,容积没有初始化大小,也没有扩容机制,一直往后新增即可
1.3 Vector
- 有序
- 线程安全
- 允许重复值
- 使用较多
- 数据结构:数组
- 使用场景: 其为重量级组件,消耗资源较多,考虑并发时候可用,无并发请用 ArrayList
- 扩容机制:初始大小为 10,元素个数超过长度 1 倍开始扩容,扩容为原容量 2 倍
2.Set
- 绝大多数是无序的
- 存值不可重复
2.1 HashSet
- 无序
- 非线程安全
- 不允许重复值,只允许放入一个 null
- 使用较多
- 数据结构:HashMap(HashSet 采用 HashCode 算法存取集合中元素)
- 使用场景:查询快,一般来说性能总是优于 TreeSet 除非我们需要排序功能时候
- 扩容机制:初始大小为 16,元素个数超过长度 0.75 倍开始扩容,扩容为原容量 2 倍
2.2 TreeSet
- 虽然取数的顺序与存的不同,但是取数的顺序每次都相同
- 非线程安全
- 不允许重复值,不允许放入 null
- 使用较多
- 数据结构:二叉树 TreeMap
- 使用场景:需要排序功能
- 扩容机制:由于底层采用二叉树实现,存储不断增加
2.3 LinkedHashSet
- 有序
- 非线程安全
- 不允许重复值,允许用 null
- 使用较多
- 数据结构:Hash 表和双向链表的结合
- 使用场景:存取有序使用
- 扩容机制:底层存在双向循环链表,不断增加数据
3.Map
参照 Set
3.1 HashMap
- 无序
- 非线程安全
- 不允许重复
- 使用较多
- 数据结构:散列表
- 使用场景:类比 HashSet 键值对
- 扩容机制:初始容量16,元素个数超过长度 0.75 倍开始扩容,扩容为原容量 2 倍
3.2 TreeMap
- 虽然取数的顺序与存的不同,但是取数的顺序每次都相同
- 非线程安全
- 不允许重复
- 使用较多
- 数据结构:红-黑二叉树
- 使用场景:类比 TreeSet 键值对
- 扩容机制:不断增加
3.3 LinkedHashMap
- 有序
- 非线程安全
- 不允许重复值,允许用 null 键和值
- 使用较多
- 数据结构:Hash 表和双向链表的结合
- 使用场景:存取有序
- 扩容机制:不断增加
3.4 HashTable
- 无序
- 线程安全
- 不允许重复值
- 使用较多
- 数据结构:散列表
- 使用场景:需要线程安全的时候
- 扩容机制:初始容量 11,元素个数超过长度 0.75 倍开始扩容,扩容后容量为原来 2 倍 + 1
4.集合与数组比较
- 集合长度可变,数组长度固定
- 集合存不同类型对象,数组存相同类型对象
- 集合是不允许存储基本数据类型和对象数据,只能存放对象的引用,Java 可以自动拆箱装箱,传入基本数据类型,可以自动装箱成对应的对象
- 有不少集合类中底层采用的就是数组
- 效率上数组无疑是高于底层采用数组的集合类的,因为这些集合类的实现本身就是基于数组的
- 正是因为数组实现的功能太弱小,所以才有应用范围更广,功能更强大的集合类的出现
5.一些问题
-
为什么不同集合类中扩容机制不同,为什么 ArrayList 扩容 1.5 倍,为什么 HashTable 扩容 2 倍 + 1
答:
[The harm is that the bigger the size of the ArrayList, the more memory allocated to it (which could go to waste if the space is not used). Since increasing the capacity of the ArrayList is much less expensive than increasing the capacity of a HashMap, it makes sense to be more conservative with the increase of capacity of an ArrayList.]:
翻译过来就是由于 ArrayList 底层是数组实现,其增加容量要比其他集合类来的更加容易,因此在增加 ArrayList 容量时应该更加保守才行,所以其他集合类都是 2 倍扩容机制,而它是 1.5 倍扩容
-
为什么 LinkedHashSet 和 LinkedHashMap 在 Set 和 Map 中是有序的
答:待补充
-
关于集合类中工具类使用的排序算法问题
答:
Collections.sort()
采用的是 合并排序,它是稳定的排序,数据接近有序时效率更高,大致是排序前先放到数组中,然后调用Arrays.sort()
,合并排序 是建立在 归并 操作上的一种有效的排序算法,其是采用 分治算法 一个典型应用 -
Arrays 工具类
答:方便操作数组,
Arrays.sort()
采用的是 快速排序算法,快速排序 并不是一种稳定的排序,即相同的值的相对位置也许会在算法结束时候发生改变,快速排序 是由冒泡排序改进过来的,采用分治的策略。大致是先拿一个“基准”,然后一个个和“基准”比较,递归到最底部即可