您的位置:首页 > 编程语言 > Java开发

java集合浅谈(一)

2015-07-31 10:25 459 查看
类库结构:



详图:



队列类图:



Deque(双端队列):两端都可以进出的队列。当我们约束从队列的一端进出时,就形成了另一种存取模式,它遵循先进后出原则,这就是栈结构。

Java集合框架之小结
http://jiangzhengjun.iteye.com/blog/553191
Java之集合类应用总结
http://www.cnblogs.com/devinzhang/archive/2012/01/25/2329434.html
Collection是最基本的集合接口,由Collection接口派生的两个接口是List和Set。JDK提供的类都继承自Collection的“子接口”,如List和Set。所有实现Collection接口的类都必须提供两个标准的构造函数:无参数的构造函数和有一个Collection参数的构造函数。前者用于创建一个空的Collection,后者用于创建一个新的Collection,允许用户复制一个Collection。不论Collection的实际类型如何,它都支持一个iterator()的方法,该方法返回一个迭代子,可逐一访问Collection中每一个元素。用法如下:

Iterator it = collection.iterator(); // 获得一个迭代子
while(it.hasNext()) {
Object obj = it.next(); // 得到下一个元素
}


容器对象仅能持有对象引用(对象的指针),而不是Copy对象信息

Collection和Map区别:

(1)Collection类型,每个位置只有一个元素。

(2)Map类型,持有key-value形式的数据——“键值对”,即其元素是成对的对象。

集合的特点:

(1)List:保证以某种特定插入顺序来维护元素顺序,即保持插入的顺序,另外元素可以重复。

    ArrayList:是用数组实现的,读取速度快,插入与删除速度慢(因为插入与删除时要移动后面的元素),适合于随机访问。ArrayList初始化时不可指定容量,如果以new ArrayList()方式创建时,初始容量为10个;如果以new ArrayList(Collection c)初始化时,容量为c.size()*1.1,即增加10%的容量;当向ArrayList中添加一个元素时,先进行容器的容量调整,如果容量不够时,则增加至原来的1.5倍加1,再然后把元素加入到容器中,即以原始容量的0.5倍比率增加。

    LinkedList:双向链表来实现,删除与插入速度快,读取速度较慢,因为它读取时是从头向尾(如果节点在链的前半部分),或从尾向头(如果节点在链的后半部分)查找元素。因此适合于元素的插入与删除操作。

    Vector:功能与ArrayList几乎相同,也是以数组实现,添加,删除,读取,设置都是基于线程同步的。当一个Iterator被创建而且正在被使用,另一个线程改变了Vector的状态,这时将抛出ConcurrentModificationException异常,因此必须捕获该异常。Vector初始化时容量可以设定,如果以new Vector()方式创建时,则初始容量为10,超过容量时以2倍容量增加。如果以new Vector(Collection c)方式创建时,初始容量为c.size()*1.1,超过时以2倍容量增加。如果以new Vector(int initialCapacity, int capacityIncrement),则以capacityIncrement容量增加。

    Stack:Stack继承自Vector,实现一个后进先出的堆栈。同步的。

    

(2)Map:Map提供的不是对象与数组的关联,而是对象和对象的关联。

    TreeMap:键以某种排序规则排序,内部以red-black(红-黑)树数据结构实现,实现了SortedMap接口,具体可参《RED-BLACK(红黑)树的实现TreeMap源码阅读

    HashMap: 以哈希表数据结构实现,查找对象时通过哈希函数计算其位置,它是为快速查询而设计的,其内部定义了一个hash表数组(Entry[] table),元素会通过哈希转换函数将元素的哈希地址转换成数组中存放的索引,如果有冲突,则使用散列链表的形式将所有相同哈希地址的元素串起来,可能通过查看HashMap.Entry的源码它是一个单链表结构。

    LinkedHashMap:继承HashMap,内部实体LinkedHashMap.Entry继承自HashMap.Entry,LinkedHashMap.Entry在HashMap.Entry的基础上新增了两个实体引用(Entry before, after),这样实体可以相互串链起来形成链,并且在LinkedHashMap中就定义了一个头节点(Entry header)用来指向循环双向链的第一个元素(通过after指向)与最后一个元素(通过before指向)。在添加一个元素时,先会通过父类HashMap将元素加入到hash表数组里,然后再会在链尾(header.before指向位置)添加(当然这一过程只是调整LinkedHashMap.Entry对象内部的before, after而已,而不是真真创建一个什么新的链表结构向里加那样);删除先从hash表数组中删除,再将被删除的元素彻底的从双向链中断开。其实在链中添加与删除操作与LinkedList是一样的,可以参考《Java集合框架之LinkedList及ListIterator实现源码分析

    WeakHashMap:WeakHashMap是一种改进的HashMap,若一个key不再被外部所引用,那么该key可以被GC回收。

    Hashtable:也是以哈希表数据结构实现的,解决冲突时与HashMap也一样也是采用了散列链表的形式,不过性能比HashMap要低。

(3)Set:set接口不保证维护元素的次序,维持它自己的内部排序,随机访问不具有意义(List或数组具备随机访问性质)。存入Set的每个元素必须是唯一的,加入Set的Object必须定义equals()方法以确保对象的唯一性,也即元素不可重复。

    HashSet:是最常用的,查询速度最快(采用散列函数),存入HashSet的对象必须定义hashCode(),因为内部以HashMap来实现, 它不保证集合的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用 null元素。此实现不是同步的。

    LinkedHashSet:继承了HashSet,因为内部使用LinkedHashMap实现(使用链表维护元素的顺序(哈希函数+链表)),所以在使用迭代器遍历Set时,结果会按元素插入的次序显示。

    TreeSet:基于TreeMap,生成一个总是处于排序状态的set,它实现了SortedSet接口,内部以 TreeMap来实现

集合中键值是否允许null

(1)List:可以有多个null,可以有重复值。

(2)HashMap:允许一个null键与多个null值,若重复键,则覆盖以前值。

(3)HashTable:不允许null键与null值(否则运行进报空指针异常)。也会覆盖重复值。基于线程同步。

(4)TreeMap:不允许null键(实际上可以插入一个null键,如果这个Map里只有一个元素是不会报错的,因为一个元素时没有进行排序操作,也就不会报空指针异常,但如果插入第二个时就会立即报错),但允许多个null值,覆盖已有键值。

(5)HashSet:能插入一个null(因为内部是以 HashMap实现 ),忽略不插入重复元素。

(6)TreeSet:不能插入null (因为内部是以 TreeMap 实现 ) ,元素不能重复,如果待插入的元素存在,则忽略不插入,对元素进行排序。

对List的选择:

(1)对于随机查询与迭代遍历操作,数组比所有的容器都要快。

(2)从中间的位置插入和删除元素,LinkedList要比ArrayList快,特别是删除操作。

(3)Vector通常不如ArrayList快,且应该避免使用,它目前仍然存在于类库中的原因是为了支持过去的代码。

(4)最佳实践:将ArrayList作为默认首选,只有当程序的性能因为经常从list中间进行插入和删除而变差的时候,才去选择LinkedList。当然了,如果只是使用固定数量的元素,就应该选择数组了。

对Map的选择:

(1)HashMap和Hashtable的效率大致相同(通常HashMap更快一点,所以HashMap有意取代Hashtable)。

(2)TreeMap通常比HashMap慢,因为要维护排序。

(3)HashMap正是为快速查询而设计的。

(4)LinkedHashMap比HashMap慢一点,因为它维护散列数据结构的同时还要维护链表。

对Set的选择:

(1)HashSet的性能总比TreeSet好(特别是最常用的添加和查找元素操作)。

(2)TreeSet存在的唯一原因是,它可以维持元素的排序状态,所以只有当你需要一个排好序的Set时,才应该使用TreeSet。

(3)对于插入操作,LinkedHashSet比HashSet略微慢一点:这是由于维护链表所带来额外开销造成的。不过,因为有了链表,遍历LinkedHashSet会比HashSet更快。

Iterator对ArrayList(LinkedList)的操作限制:

(1)刚实例化的迭代器如果还没有进行后移(next)操作是不能马上进行删除与修改操作的。

(2)可以用ListIterator对集合连续添加与修改,但不能连续删除。

(3)进行添加操作后是不能立即进行删除与修改操作的。

(4)进行删除操作后可以进行添加,但不能进行修改操作。

(5)进行修改后是可以立即进行删除与添加操作的。

通过迭代器修改集合结构
在使用迭代器遍历集合时,我们不能通过集合本身来修改集合的结构(添加、删除),只能通过迭代器来操作。

下面是对HashMap删除操作的测试,其它集合也是这样:

package com.test;

import java.util.*;
import java.util.Map.Entry;

public class Test {
public static void main(String[] args) {
Map map = new HashMap();
map.put(1, 1);
map.put(2, 3);
Set entrySet = map.entrySet();
Iterator it = entrySet.iterator();
while (it.hasNext()) {
Entry entry = (Entry) it.next();
/*
* 可以通过迭代器来修改集合结构,但前提是要在已执行过next或前移操作,
* 否则会抛异常:IllegalStateException
*/
//it.remove();

/*
* 抛异常:ConcurrentModificationException 因为通过迭代器操作时,
* 不能使用集合本身来修改集合的结构
*/
// map.remove(entry.getKey());
}//end while
System.out.println(map);
}
}


在多线程环境下,对于非同步的集合和Map,可以用类似List list = Collections.synchronizedList(new LinkedList(...));或 Collections.synchronizedMap(originMap) 实现其同步,或者其他手动同步的方法。

JAVA集合小结
http://www.blogjava.net/EvanLiu/archive/2007/11/12/159884.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: