java se集合框架(一)概述
Java集合框架提供了数据持有对象的方式,提供了对数据集合的操作。Java集合框架位于 java.util 包下,主要有三个大类:Collection(接口)、Map(接口)、集合工具类。
集合框架图
Collection
- ArrayList:线程不同步。默认初始容量为10,当数组大小不足时容量扩大为1.5倍。为追求效率,ArrayList没有实现同步(synchronized),如果需要多个线程并发访问,用户可以手动同步,也可使用Vector替代。
- LinkedList:线程不同步。双向链接实现。LinkedList同时实现了List接口和Deque接口,也就是说它既可以看作一个顺序容器,又可以看作一个队列(Queue),同时又可以看作一个栈(Stack)。这样看来,LinkedList简直就是个全能冠军。当你需要使用栈或者队列时,可以考虑使用LinkedList,一方面是因为Java官方已经声明不建议使用Stack类,更遗憾的是,Java里根本没有一个叫做Queue的类(它是个接口名字)。关于栈或队列,现在的首选是ArrayDeque,它有着比LinkedList(当作栈或队列使用时)有着更好的性能。
- Stack and Queue:Java里有一个叫做Stack的类,却没有叫做Queue的类(它是个接口名字)。当需要使用栈时,Java已不推荐使用Stack,而是推荐使用更高效的ArrayDeque;既然Queue只是一个接口,当需要使用队列时也就首选ArrayDeque了(次选是LinkedList)。
- Vector:线程同步。默认初始容量为10,当数组大小不足时容量扩大为2倍。它的同步是通过Iterator方法加synchronized实现的。
- Stack:线程同步。继承自Vector,添加了几个方法来完成栈的功能。现在已经不推荐使用Stack,在栈和队列中有限使用ArrayDeque,其次是LinkedList。
- TreeSet:线程不同步,内部使用NavigableMap操作。默认元素“自然顺序”排列,可以通过Comparator改变排序。TreeSet里面有一个TreeMap(适配器模式)
- HashSet:线程不同步,内部使用HashMap进行数据存储,提供的方法基本都是调用HashMap的方法,所以两者本质是一样的。集合元素可以为NULL。
- Set:Set是一种不包含重复元素的Collection,Set最多只有一个null元素。Set集合通常可以通过Map集合通过适配器模式得到。
-
PriorityQueue:Java中PriorityQueue实现了Queue接口,不允许放入null元素;其通过堆实现,具体说是通过完全二叉树(complete binary tree)实现的小顶堆(任意一个非叶子节点的权值,都不大于其左右子节点的权值),也就意味着可以通过数组来作为PriorityQueue的底层实现。
优先队列的作用是能保证每次取出的元素都是队列中权值最小的(Java的优先队列每次取最小元素,C++的优先队列每次取最大元素)。这里牵涉到了大小关系,元素大小的评判可以通过元素本身的自然顺序(natural
ordering),也可以通过构造时传入的比较器(Comparator,类似于C++的仿函数)。 - NavigableSet:添加了搜索功能,可以对给定元素进行搜索:小于、小于等于、大于、大于等于,放回一个符合条件的最接近给定元素的 key。
- EnumSet:线程不同步。内部使用Enum数组实现,速度比HashSet快。只能存储在构造函数传入的枚举类的枚举值。
Map
-
TreeMap:线程不同步,基于 红黑树 (Red-Black tree)的NavigableMap
实现,能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器,当用Iterator遍历TreeMap时,得到的记录是排过序的。
TreeMap底层通过红黑树(Red-Black tree)实现,也就意味着containsKey(), get(), put(), remove()都有着log(n)的时间复杂度。其具体算法实现参照了《算法导论》。 -
HashMap:线程不同步。根据key的hashcode进行存储,内部使用静态内部类Node的数组进行存储,默认初始大小为16,每次扩大一倍。当发生Hash冲突时,采用拉链法(链表)。JDK1.8中:当单个桶中元素个数大于等于8时,链表实现改为红黑树实现;当元素个数小于6时,变回链表实现。由此来防止hashCode攻击。
Java HashMap采用的是冲突链表方式。
HashMap是Hashtable的轻量级实现,可以接受为null的键值(key)和值(value),而Hashtable不允许。 - LinkedHashMap:保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的。也可以在构造时用带参数,按照应用次数排序。在遍历的时候会比HashMap慢,不过有种情况例外,当HashMap容量很大,实际数据较少时,遍历起来可能会比LinkedHashMap慢,因为LinkedHashMap的遍历速度只和实际数据有关,和容量无关,而HashMap的遍历速度和他的容量有关。
- HashTable:线程安全,HashMap的迭代器(Iterator)是fail-fast迭代器。HashTable不能存储NULL的key和value。
-
WeakHashMap:从名字可以看出它是某种 Map。它的特殊之处在于 WeakHashMap 里的entry可能会被GC自动删除,即使程序员没有调用remove()或者clear()方法。WeakHashMap的存储结构类似于HashMap
既然有 WeekHashMap,是否有 WeekHashSet 呢?答案是没有!不过Java Collections工具类给出了解决方案,Collections.newSetFromMap(Map
工具类
- Collections、Arrays:集合类的一个工具类帮助类,其中提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作。
- Comparable、Comparator:一般是用于对象的比较来实现排序,两者略有区别。
类设计者没有考虑到比较问题而没有实现Comparable接口。这是我们就可以通过使用Comparator,这种情况下,我们是不需要改变对象的。
一个集合中,我们可能需要有多重的排序标准,这时候如果使用Comparable就有些捉襟见肘了,可以自己继承Comparator提供多种标准的比较器进行排序。
说明:线程不同步的时候可以通过,Collections.synchronizedList() 方法来包装一个线程同步方法.
通用实现