集合
线程安全: Vector,HashTable
非线程安全:ArrayList,HashMap,LinkedList,TreeMap,HashSet,TreeSet
Collection接口
Collection是最基本的集合接口,它不提供直接的实现,如List和Set都是继承Collection接口的。
List接口(有序)(可重复)
List接口为Collection直接接口。List 所代表的是有序的 Collection,即它用某种特定的插入顺序来维护元素顺序。用户可以对列表中每个元素的插入位置进行精确地控制,同时可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。实现 List 接口的集合主要有:ArrayList、LinkedList、Vector、Stack。
ArrayList
ArrayList是一个动态数组,允许任何符合规则的元素插入甚至null。每一个ArrayList都有一个初始容量(10),该容量代表了数组大小。随着容器中的元素不断增加。在每次像容器中增加元素的同时都会进行容量检查,当快溢出时就会进行扩容操作。所以如果我们明确所插入元素的多少,最好指定一个初始容量值,避免过多的进行扩容而浪费时间、效率。
LinkedList
同样实现 List 接口的 LinkedList 与 ArrayList 不同,**ArrayList是一个动态数组,而 LinkedList 是一个双向链表。**所以它除了有 ArrayList 的基本操作方法外还额外提供了 get,remove,insert 方法在 LinkedList 的首部或尾部。
LinkedList不能随机访问,它所有的操作都是要按照双重链表的需要执行。在列表中索引的操作将从开头或结尾遍历列表(从靠近指定索引的一端)。这样做的好处就是可以通过较低的代价在 List 中进行插入和删除操作。
与 ArrayList 一样,LinkedList 也是非同步的。如果多个线程同时访问一个 List,则必须自己实现访问同步。一种解决方法是在创建 List 时构造一个同步的 List:List list =Collections.synchronizedList(new LinkedList(…));
Vector
与 ArrayList 相似,但是 Vector 是同步的。所以说 Vector 是线程安全的动态数组。它的操作与 ArrayList 几乎一样。
Stack
Stack继承自Vactor,实现先进后出。Stack提供额外的方法使得Vactor得以被当作堆栈使用。其中push和pop方法,还有peek方法得到栈顶元素,empty测试堆栈是否为空,search方法检测一个元素在堆栈中的位置。Stack刚创建后是空栈。
Set接口(HashSet无序)(不可重复)
**Set是一种不包括重复元素的Collection。**它维持自己的内部排序,所以随机访问没有任何意义。与List一样,Set可以插入null,但是仅有一个。由于Set接口的特殊性,所有传入Set集合的元素都必须不同,同时要注意任何可变对象,如果对集合中元素进行操作时,导致Set集合中有两个相同的元素,则必定会产生,某些问题。实现Set接口的集合有:EnumSet,HashSet,TreeSet。
EnumSet
是枚举的专用 Set。所有的元素都是枚举类型。
HashSet
HashSet 堪称查询速度最快的集合,因为其内部是以 HashCode 来实现的。它内部元素的顺序是由哈希码来决定的,所以它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。
TreeSet
基于 TreeMap,生成一个总是处于排序状态的 set,内部以 TreeMap 来实现。它是使用元素的自然顺序对元素进行排序,或者根据创建 Set 时提供的 Comparator 进行排序,具体取决于使用的构造方法。
Map
Map 与 List、Set 接口不同,它是由一系列键值对组成的集合,提供了 key 到 Value 的映射。同时它也没有继承 Collection。在 Map 中它保证了 key 与 value 之间的一一对应关系。也就是说一个 key 对应一个 value,所以它不能存在相同的 key 值,当然 value 值可以相同。实现 map 的有:HashMap、TreeMap、HashTable、Properties、EnumMap。
HashMap
以哈希表数据结构实现,查找对象时通过哈希函数计算其位置,它是为快速查询而设计的。
TreeMap
键以某种排序规则排序,内部以 red-black(红-黑)树数据结构实现,实现了 SortedMap 接口。
HashTable
也是以哈希表数据结构实现的,解决冲突时与 HashMap 也一样也是采用了散列链表的形式,不过性能比 HashMap 要低。
Queue
队列,它主要分为两大类,一类是阻塞式队列,队列满了以后再插入元素则会抛出异常,主要包括 ArrayBlockQueue、PriorityBlockingQueue、LinkedBlockingQueue。另一种队列则是双端队列,支持在头、尾两端插入和移除元素,主要包括:ArrayDeque、LinkedBlockingDeque、LinkedList。
异同点
-
Vector 和 ArrayList
不考虑线程安全因素,一般用线程不安全的ArrayList效率比较高。
如果在集合中使用数据量较大的数据,用Vector有一定优势。
根据时间复杂度判断,查找指定位置的数据,用Vector和ArrayList都可以,而如果移动一个指定位置的数据花费的时间为 0(n-i)n 为总长度,这个时候就应该考虑到使用 LinkList。
ArrayList 和 Vector 是采用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,都允许直接序号索引元素,但是插入数据要设计到数组元素移动等内存操作,所以索引数据快插入数据慢,Vector 由于使用了 synchronized 方法(线程安全)所以性能上比 ArrayList 要差
-
ArrayList 和 LinkedList
ArrayList 是实现了基于动态数组的数据结构,LinkedList 基于链表的数据结构。
对于随机访问 get 和 set,ArrayList 觉得优于 LinkedList,因为LinkedList 要移动指针。
对于新增和删除操作 add 和 remove,LinedList 比较占优势,因为 ArrayList 要移动数据。(若是单个数据还是使用ArrayList,批量使用LinkedList)
-
HashMap 和 TreeMap
HashMap 通过 hashcode 对其内容进行快速查找,而 TreeMap 中所有的元素都保持着某种固定的顺序,如果你需要得到一个有序的结果你就应该使用 TreeMap(HashMap 中元素的排列顺序是不固定的)。
HashMap 通过 hashcode 对其内容进行快速查找,而 TreeMap 中所有的元素都保持着某种固定的顺序,如果你需要得到一个有序的结果你就应该使用 TreeMap。
在 Map 中插入、删除和定位元素,HashMap 是最好的选择。但如果您要按自然顺序或自定义顺序遍历键,那么 TreeMap 会更好。使用 HashMap 要求添加的键类明确定义了 hashCode() 和 equals() 的实现。 这个 TreeMap 没有调优选项,因为该树总处于平衡状态。
-
HashTable 和 HashMap
历史原因:HashTable 是基于陈旧的 Dictionary 类的,HashMap 是Java 1.2 引进的 Map 接口的一个实现。
同步性:HashTable 是线程安全的,也就是说是同步的,而 HashMap 是线程序不安全的,不是同步的 。
值:只有 HashMap 可以让你将空值作为一个表的条目的 key 或value。
对集合的选择
-
对 List 的选择
对于随机查询与迭代遍历操作,数组比所有的容器都要快。所以在随机访问中一般使用 ArrayList。
LinkedList 使用双向链表对元素的增加和删除提供了非常好的支持,而 ArrayList 执行增加和删除元素需要进行元素位移。
对于 Vector 而已,我们一般都是避免使用。
将 ArrayList 当做首选,毕竟对于集合元素而已我们都是进行遍历,只有当程序的性能因为 List 的频繁插入和删除而降低时,再考虑 LinkedList。
-
对Set的选择
HashSet 由于使用 HashCode 实现,所以在某种程度上来说它的性能永远比 TreeSet 要好,尤其是进行增加和查找操作。
虽然 TreeSet 没有 HashSet 性能好,但是由于它可以维持元素的排序,所以它还是存在用武之地的。
-
对Map的选择
HashMap 与 HashSet 同样,支持快速查询。但HashTable的速度慢于HashMap,所以 HashMap 在查询方面可以取代 HashTable。
2、由于 TreeMap 需要维持内部元素的顺序,所以它通常要比 HashMap 和 HashTable 慢。