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