一 Java集合体系
Java集合大致可分为2个体系,一个Collection;一个Map;
- Collection :主要由List、Set、Queue接口组成,List代表有序、重复的集合;其中Set代表无序、不可重复的集合;Java 5 又增加了Queue体系集合,代表一种队列集合实现。
- Map:则代表具有映射关系的键值对集合。
java.util.Collection 下的接口和继承类关系简易结构图:
java.util.Map 下的接口和继承类关系简易结构图:
二 List,Queue,Set,Map 的区别
- List(顺序): 存储的元素是有序的、可重复的。
- Queue():是一个队列集合,队列通常是指“先进先出”(FIFO)的容器。新元素插入(offer)到队列的尾部,访问元素(poll)操作会返回队列头部的元素。通常,队列不允许随机访问队列中的元素。LinkedList类实现了Queue接口,因此我们可以把LinkedList当成Queue来用。
- Set(唯一): 存储的元素是无序的、不可重复的。
- Map(k-v形式): 使用键值对(kye-value)存储,Key 是无序的、不可重复的,value 是无序的、可重复的,每个键最多映射到一个值。
三 有序列表(List)
List集合的特点就是存取有序,可以存储重复的元素,可以用下标进行元素的操作
List主要实现类:ArrayList、LinkedList、Vector、Stack
- ArrayList
ArrayList 是一个动态数组结构(Object[]
数组),支持随机存取,尾部插入删除方便,内部插入删除效率低(因为要移动数组元素);如果内部数组容量不足则自动扩容,因此当数组很大时,效率较低。
- LinkedList
LinkedList 是一个双向链表结构(JDK1.6 之前为循环链表,JDK1.7 取消了循环),在任意位置插入删除都很方便,但是不支持随机取值,每次都只能从一端开始遍历,直到找到查询的对象,然后返回;不过,它不像 ArrayList 那样需要进行内存拷贝,因此相对来说效率较高,但是因为存在额外的前驱和后继节点指针,因此占用的内存比 ArrayList 多一些。
- Vector
Vector 也是一个动态数组结构,一个元老级别的类,早在 jdk1.1 就引入进来类,之后在 jdk1.2 里引进 ArrayList,ArrayList 大部分的方法和 Vector 比较相似,两者不同的地方,Vector 是允许同步访问的,Vector 中的操作是线程安全的,但是效率低,而 ArrayList 所有的操作都是异步的,执行效率高,但不安全!
关于Vector
,现在用的很少了,因为里面的get
、set
、add
等方法都加了synchronized
,所以,执行效率会比较低,如果需要在多线程中使用,可以采用下面语句创建 ArrayList 对象
List<Object> list =Collections.synchronizedList(new ArrayList<Object>());
也可以考虑使用复制容器 java.util.concurrent.CopyOnWriteArrayList
进行操作
CopyOnWriteArrayList<Object> cowList = new CopyOnWriteArrayList<String>(Object);
- Stack
Stack 是 Vector 的一个子类,本质也是一个动态数组结构,不同的是,它的数据结构是先进后出,取名叫栈
关于Stack
,现在用的也很少,因为有个ArrayDeque
双端队列,可以替代Stack
所有的功能,并且执行效率比它高
四 集(Set)
Set集合的特点:元素不重复,存取无序,无下标
Set主要实现类:HashSet、LinkedHashSet 和 TreeSet
Set 集合的实现,基本都是基于 Map 中的键做文章,使用 Map 中键不能重复、无序的特性;所以,我们只需要重点关注 Map 的实现即可
- HashSet
基于 HashMap
实现的,底层采用 HashMap
来保存元素,特性同 HashMap
- LinkedHashSet
LinkedHashSet底层也是基于 LinkedHashMap 的k
实现的,一样元素不可重复,特性同 LinkedHashMap
- TreeSet
TreeSet 也是基于 TreeMap 的k
实现的,同样元素不可重复,特性同 TreeMap
五 队列(Queue)
Queue是一个队列集合,队列通常是指“先进先出”(FIFO)的容器。新元素插入(offer)到队列的尾部,访问元素(poll)操作会返回队列头部的元素。通常,队列不允许随机访问队列中的元素
Queue主要实现类:ArrayDeque、LinkedList、PriorityQueue
- ArrayDeque
ArrayQueue是一个基于数组实现的双端队列,可以想象,在队列中存在两个指针,一个指向头部,一个指向尾部,因此它具有“FIFO队列”及“栈”的方法特性
- LinkedList
LinkedList是List接口的实现类,也是Deque的实现类,底层是一种双向链表的数据结构,在上面咱们也有所介绍,LinkedList可以根据索引来获取元素,增加或删除元素的效率较高,如果查找的话需要遍历整合集合,效率较低,LinkedList同时实现了stack、Queue、PriorityQueue的所有功能
- PriorityQueue
PriorityQueue也是一个队列的实现类,此实现类中存储的元素排列并不是按照元素添加的顺序进行排列,而是内部会按元素的大小顺序进行排列,是一种能够自动排序的队列
六 映射表(Map)
Map是一个双列集合,其中保存的是键值对,键要求保持唯一性,值可以重复
Map 主要实现类:HashMap、LinkedHashMap、TreeMap、IdentityHashMap、WeakHashMap、Hashtable、Properties
- HashMap
继承自AbstractMap,key 不可重复,因为使用的是哈希表存储元素,所以输入的数据与输出的数据,顺序基本不一致,另外,HashMap最多只允许一条记录的 key 为 null;
JDK1.8 之前 HashMap
由数组+链表组成的,数组是 HashMap
的主体,链表则是主要为了解决哈希冲突而存在的(“拉链法”解决冲突)。JDK1.8 以后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为 8)(将链表转换成红黑树前会判断,如果当前数组的长度小于 64,那么会选择先进行数组扩容,而不是转换为红黑树)时,将链表转化为红黑树,以减少搜索时间
- LinkedHashMap
HashMap 的子类,内部使用链表数据结构来记录插入的顺序,使得输入的记录顺序和输出的记录顺序是相同的。LinkedHashMap与HashMap最大的不同处在于,LinkedHashMap输入的记录和输出的记录顺序是相同的
LinkedHashMap
继承自 HashMap
,所以它的底层仍然是基于拉链式散列结构即由数组和链表或红黑树组成。另外,LinkedHashMap
在上面结构的基础上,增加了一条双向链表,使得上面的结构可以保持键值对的插入顺序。同时通过对链表进行相应的操作,实现了访问顺序相关逻辑
- TreeMap
能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器,当用 Iterator 遍历时,得到的记录是排过序的;如需使用排序的映射,建议使用 TreeMap。TreeMap实际使用的比较少;红黑树(自平衡的排序二叉树)
- IdentityHashMap
继承自AbstractMap,与HashMap有些不同,在获取元素的时候,通过==
代替equals ()
来进行判断,比较的是内存地址
- WeakHashMap
WeakHashMap继承自AbstractMap,被称为缓存Map,向WeakHashMap中添加元素,再次通过键调用方法获取元素方法时,不一定获取到元素值,因为WeakHashMap 中的 Entry 可能随时被 GC 回收
- HashTable
Hashtable,一个元老级的类,键值不能为空,与HashMap不同的是,方法都加了synchronized
同步锁,是线程安全的,但是效率上,没有HashMap快
同时,HashMap 是 HashTable 的轻量级实现,他们都完成了Map 接口,区别在于 HashMap 允许K和V为空,而HashTable不允许K和V为空,由于非线程安全,效率上可能高于 Hashtable
如果需要在多线程环境下使用HashMap,可以使用如下的同步器来实现或者使用并发工具包中的ConcurrentHashMap
类
- Properties
Properties继承自HashTable,Properties新增了load()和store()方法,可以直接导入或者将映射写入文件,另外,Properties的键和值都是String类型