集合包是Java中最重要的包,起码自己是这么认为的,所有对于数据集合的操作,都离不开它们。Java集合框架提供了高性能的数据结构和算法,主要由一组用来操作对象的接口组成。不同的接口描述一组不同的数据类型,如我们常见的List接口、Map接口、Set接口。它最常用的有Collection和Map两个接口的实现类,Collection用于存放多个单对象,Map用于存放key-value形式的键值对。
一、Java集合的框架示意图解析
UML图标简介
1)短虚线框框表示接口、实线框框表示类
2)虚线+空心箭头表示泛化的关系,类与类、接口与接口的泛化就是继承,类与接口的泛化就是实现。
3)虚线+实心箭头表示依赖关系,这里可认为是调用的关系。
二、集合框架解析:
1、框架基本对象
Collection、Map、Iterator是三个最顶层的接口。Collection调用了Iterator,Map调用了Collection。
Collection包括两个子接口:List和Set。这几个接口主要包括8个实现类。
2、基本接口
Collection : Collection层次结构中的根接口,一个Collection代表一组Object的集合,这些Object被称作Collection的元素。
Iterator : 对集合进行迭代的迭代器。
Map : 一组成对的键-值对象,即所持有的是key-value pairs。Map中不能有重复的key,拥有自己的内部排列机制。
List : 继承 Collection,允许重复,以元素安插的次序来放置元素,不会重新排列。
Set : 继承Collection,内部元素不允许重复,使用自己内部的一个排列机制。
ListIterator:系列表迭代器,允许按任一方向遍历列表、迭代期间修改列表,并获得迭代器在列表中的当前位置。
3、主要的实现类
ArrayList
基于数组方式实现,无容量的限制 -
在执行插入元素时可能要扩容,在删除元素时并不会减小数组的容量;在查找元素时要遍历数组;删除元素时,需要将当前元素的所在位置后的元素通过复制向前移动一位
- 非线程安全
- 基于双向的链表机制实现
-
在插入元素时,必须创建一个新的Entry对象,并切换相应元素的前后元素的引用;在查找元素时,必须遍历链表;在删除元素时,要遍历链表,找到要删除的元素,然后从链表上将此元素删除即可以
- 非线程安全
- 基于HashMap来实现,无容量限制
- 不能通过get(i)的方式来获取指定位置的元素,只能通过遍历iterator方法来获取
- 非线程安全
- 具有HashSet的查询速度,且内部使用链表维护元素的顺序
- 在使用迭代遍历Set时,结果会按照元素插入的次序显示
- 非线程安全
- 基于TreeMap来实现,支持排序
- 不能通过get(i)的方式来获取指定位置的元素,只能通过遍历iterator方法来获取
- 非线程安全
- Map实现中最常用的。采用数组方式存储key、value构成的Entry对象,无容量限制
- 在遍历时无法保证元素的顺序
- 基于Keyhash需找Entry对象存放到数组的位置,对于hash冲突采用链表的方式来解决
- 在插入元素时可能会扩大数组的容量,在扩大容量时会重新计算hash,并复制到新的数组中
- 非线程安全
- 类似于HashMap,查看“key”或者“key-value”对的顺序是其插入次序,或者是最近最少使用的次序
- 非线程安全
- 基于红黑树实现,无容量限制
- 得到的结果是一个有序的集合
- 非线程安全
三、如何选择容器
- 根据功能需求来选择用List、Set还是Map
- 根据功能需要选择接口具体的实现类。
- 根据场景中的存储的数据量、及操作(例如增加元素、删除元素)来考虑或者测试所选容器的性能。其它:考虑线程安全、并发等
四、小结
- Collection保存单一的元素,而Map保存相关联的键值对;
- List能够自动扩充容量,但是List不能保存基本类型,只能保存Object的引用,因此必须对从容器中去除的Object结果做类型转换;
- 如果要进行大量的随机访问,就是用ArrayList;如果要经常从表中间插入或删除元素,则应该使用LinkedList;
- 队列、双向队列以及栈的行为,由LinkedList支持;
- HashMap着重于快速访问;而TreeMap保持“键”始终处于排序状态;
- Set不接受重复元素。HashSet提供最快的查询速度;
- 程序中不应该再使用过时的Vector、Hashtable、Stack;
- 列表优先于数组;
-
返回零长度的数组或者集合,而不是null;
- 没有最好的容器,要根据不同的需要选择不同的容器,以达到功能的需求和效率的最优。