JAVA的容器---List Map Set
2010-09-25 14:59
423 查看
JAVA
的容器---List,Map,Set
Collection
├List
│├LinkedList
│├ArrayList
│└Vector
│
└Stack
└Set
Map
├Hashtable
├HashMap
└WeakHashMap
Collection
接口
Collection
是最基本的集合接口,一个Collection
代表一组Object
,即Collection
的元素(Elements
)。一些 Collection
允许相同的元素而另一些不行。一些能排序而另一些不行。Java SDK
不提供直接继承自Collection
的类,Java SDK
提供的类都是继承自Collection
的“
子接口”
如List
和Set
。
所有实现Collection
接口的类都必须提供两个标准的构造函数:无参数的构造函数用于创建一个空的Collection
,有一个 Collection
参数的构造函数用于创建一个新的Collection
,这个新的Collection
与传入的Collection
有相同的元素。后一个构造函数允许用户复制一个Collection
。
如何遍历Collection
中的每一个元素?不论Collection
的实际类型如何,它都支持一个iterator()
的方法,该方法返回一个迭代子,使用该迭代子即可逐一访问Collection
中每一个元素。典型的用法如下:
Iterator it = collection.iterator(); //
获得一个迭代子
while(it.hasNext()) {
Object obj = it.next(); //
得到下一个元素
}
由Collection
接口派生的两个接口是List
和Set
。
List
接口
List
是有序的Collection
,使用此接口能够精确的控制每个元素插入的位置。用户能够使用索引(元素在List
中的位置,类似于数组下标)来访问List
中的元素,这类似于Java
的数组。
和下面要提到的Set
不同,List
允许有相同的元素。
除了具有Collection
接口必备的iterator()
方法外,List
还提供一个listIterator()
方法,返回一个 ListIterator
接口,和标准的Iterator
接口相比,ListIterator
多了一些add()
之类的方法,允许添加,删除,设定元素,还能向前或向后遍历。
实现List
接口的常用类有LinkedList
,ArrayList
,Vector
和Stack
。
LinkedList
类
LinkedList
实现了List
接口,允许null
元素。此外LinkedList
提供额外的get
,remove
,insert
方法在 LinkedList
的首部或尾部。这些操作使LinkedList
可被用作堆栈(stack
),队列(queue
)或双向队列(deque
)。
注意LinkedList
没有同步方法。如果多个线程同时访问一个List
,则必须自己实现访问同步。一种解决方法是在创建List
时构造一个同步的List
:
List list = Collections.synchronizedList(new LinkedList(...));
ArrayList
类
ArrayList
实现了可变大小的数组。它允许所有元素,包括null
。ArrayList
没有同步。
size
,isEmpty
,get
,set
方法运行时间为常数。但是add
方法开销为分摊的常数,添加n
个元素需要O(n)
的时间。其他的方法运行时间为线性。
每个ArrayList
实例都有一个容量(Capacity
),即用于存储元素的数组的大小。这个容量可随着不断添加新元素而自动增加,但是增长算法并没有定义。当需要插入大量元素时,在插入前可以调用ensureCapacity
方法来增加ArrayList
的容量以提高插入效率。
和LinkedList
一样,ArrayList
也是非同步的(unsynchronized
)。
Vector
类
Vector
非常类似ArrayList
,但是Vector
是同步的。由Vector
创建的Iterator
,虽然和ArrayList
创建的 Iterator
是同一接口,但是,因为Vector
是同步的,当一个Iterator
被创建而且正在被使用,另一个线程改变了Vector
的状态(例如,添加或删除了一些元素),这时调用Iterator
的方法时将抛出ConcurrentModificationException
,因此必须捕获该异常。
Stack
类
Stack
继承自Vector
,实现一个后进先出的堆栈。Stack
提供5
个额外的方法使得Vector
得以被当作堆栈使用。基本的push
和pop
方法,还有peek
方法得到栈顶的元素,empty
方法测试堆栈是否为空,search
方法检测一个元素在堆栈中的位置。Stack
刚创建后是空栈。
Set
接口
Set
是一种不包含重复的元素的Collection
,即任意的两个元素e1
和e2
都有e1.equals(e2)=false
,Set
最多有一个null
元素。
很明显,Set
的构造函数有一个约束条件,传入的Collection
参数不能包含重复的元素。
请注意:必须小心操作可变对象(Mutable Object
)。如果一个Set
中的可变元素改变了自身状态导致Object.equals(Object)=true
将导致一些问题。
Map
接口
请注意,Map
没有继承Collection
接口,Map
提供key
到value
的映射。一个Map
中不能包含相同的key
,每个key
只能映射一个 value
。Map
接口提供3
种集合的视图,Map
的内容可以被当作一组key
集合,一组value
集合,或者一组key-value
映射。
Hashtable
类
Hashtable
继承Map
接口,实现一个key-value
映射的哈希表。任何非空(non-null
)的对象都可作为key
或者value
。
添加数据使用put(key, value)
,取出数据使用get(key)
,这两个基本操作的时间开销为常数。
Hashtable
通过initial capacity
和load factor
两个参数调整性能。通常缺省的load factor 0.75
较好地实现了时间和空间的均衡。增大load factor
可以节省空间但相应的查找时间将增大,这会影响像get
和put
这样的操作。
使用Hashtable
的简单示例如下,将1
,2
,3
放到Hashtable
中,他们的key
分别是”one”
,”two”
,”three”
:
Hashtable numbers = new Hashtable();
numbers.put(“one”, new Integer(1));
numbers.put(“two”, new Integer(2));
numbers.put(“three”, new Integer(3));
要取出一个数,比如2
,用相应的key
:
Integer n = (Integer)numbers.get(“two”);
System.out.println(“two = ” + n);
由于作为key
的对象将通过计算其散列函数来确定与之对应的value
的位置,因此任何作为key
的对象都必须实现hashCode
和equals
方法。hashCode
和equals
方法继承自根类Object
,如果你用自定义的类当作key
的话,要相当小心,按照散列函数的定义,如果两个对象相同,即obj1.equals(obj2)=true
,则它们的hashCode
必须相同,但如果两个对象不同,则它们的hashCode
不一定不同,如果两个不同对象的hashCode
相同,这种现象称为冲突,冲突会导致操作哈希表的时间开销增大,所以尽量定义好的hashCode()
方法,能加快哈希表的操作。
如果相同的对象有不同的hashCode
,对哈希表的操作会出现意想不到的结果(期待的get
方法返回null
),要避免这种问题,只需要牢记一条:要同时复写equals
方法和hashCode
方法,而不要只写其中一个。
Hashtable
是同步的。
HashMap
类
HashMap
和Hashtable
类似,不同之处在于HashMap
是非同步的,并且允许null
,即null value
和null key
。,但是将HashMap
视为Collection
时(values()
方法可返回Collection
),其迭代子操作时间开销和HashMap
的容量成比例。因此,如果迭代操作的性能相当重要的话,不要将HashMap
的初始化容量设得过高,或者load factor
过低。
WeakHashMap
类
WeakHashMap
是一种改进的HashMap
,它对key
实行“
弱引用”
,如果一个key
不再被外部所引用,那么该key
可以被GC
回收。
总结
如果涉及到堆栈,队列等操作,应该考虑用List
,对于需要快速插入,删除元素,应该使用LinkedList
,如果需要快速随机访问元素,应该使用ArrayList
。
如果程序在单线程环境中,或者访问仅仅在一个线程中进行,考虑非同步的类,其效率较高,如果多个线程可能同时操作一个类,应该使用同步的类。
要特别注意对哈希表的操作,作为key
的对象要正确复写equals
和hashCode
方法。
尽量返回接口而非实际的类型,如返回List
而非ArrayList
,这样如果以后需要将ArrayList
换成LinkedList
时,客户端代码不用改变。这就是针对抽象编程。
的容器---List,Map,Set
Collection
├List
│├LinkedList
│├ArrayList
│└Vector
│
└Stack
└Set
Map
├Hashtable
├HashMap
└WeakHashMap
Collection
接口
Collection
是最基本的集合接口,一个Collection
代表一组Object
,即Collection
的元素(Elements
)。一些 Collection
允许相同的元素而另一些不行。一些能排序而另一些不行。Java SDK
不提供直接继承自Collection
的类,Java SDK
提供的类都是继承自Collection
的“
子接口”
如List
和Set
。
所有实现Collection
接口的类都必须提供两个标准的构造函数:无参数的构造函数用于创建一个空的Collection
,有一个 Collection
参数的构造函数用于创建一个新的Collection
,这个新的Collection
与传入的Collection
有相同的元素。后一个构造函数允许用户复制一个Collection
。
如何遍历Collection
中的每一个元素?不论Collection
的实际类型如何,它都支持一个iterator()
的方法,该方法返回一个迭代子,使用该迭代子即可逐一访问Collection
中每一个元素。典型的用法如下:
Iterator it = collection.iterator(); //
获得一个迭代子
while(it.hasNext()) {
Object obj = it.next(); //
得到下一个元素
}
由Collection
接口派生的两个接口是List
和Set
。
List
接口
List
是有序的Collection
,使用此接口能够精确的控制每个元素插入的位置。用户能够使用索引(元素在List
中的位置,类似于数组下标)来访问List
中的元素,这类似于Java
的数组。
和下面要提到的Set
不同,List
允许有相同的元素。
除了具有Collection
接口必备的iterator()
方法外,List
还提供一个listIterator()
方法,返回一个 ListIterator
接口,和标准的Iterator
接口相比,ListIterator
多了一些add()
之类的方法,允许添加,删除,设定元素,还能向前或向后遍历。
实现List
接口的常用类有LinkedList
,ArrayList
,Vector
和Stack
。
LinkedList
类
LinkedList
实现了List
接口,允许null
元素。此外LinkedList
提供额外的get
,remove
,insert
方法在 LinkedList
的首部或尾部。这些操作使LinkedList
可被用作堆栈(stack
),队列(queue
)或双向队列(deque
)。
注意LinkedList
没有同步方法。如果多个线程同时访问一个List
,则必须自己实现访问同步。一种解决方法是在创建List
时构造一个同步的List
:
List list = Collections.synchronizedList(new LinkedList(...));
ArrayList
类
ArrayList
实现了可变大小的数组。它允许所有元素,包括null
。ArrayList
没有同步。
size
,isEmpty
,get
,set
方法运行时间为常数。但是add
方法开销为分摊的常数,添加n
个元素需要O(n)
的时间。其他的方法运行时间为线性。
每个ArrayList
实例都有一个容量(Capacity
),即用于存储元素的数组的大小。这个容量可随着不断添加新元素而自动增加,但是增长算法并没有定义。当需要插入大量元素时,在插入前可以调用ensureCapacity
方法来增加ArrayList
的容量以提高插入效率。
和LinkedList
一样,ArrayList
也是非同步的(unsynchronized
)。
Vector
类
Vector
非常类似ArrayList
,但是Vector
是同步的。由Vector
创建的Iterator
,虽然和ArrayList
创建的 Iterator
是同一接口,但是,因为Vector
是同步的,当一个Iterator
被创建而且正在被使用,另一个线程改变了Vector
的状态(例如,添加或删除了一些元素),这时调用Iterator
的方法时将抛出ConcurrentModificationException
,因此必须捕获该异常。
Stack
类
Stack
继承自Vector
,实现一个后进先出的堆栈。Stack
提供5
个额外的方法使得Vector
得以被当作堆栈使用。基本的push
和pop
方法,还有peek
方法得到栈顶的元素,empty
方法测试堆栈是否为空,search
方法检测一个元素在堆栈中的位置。Stack
刚创建后是空栈。
Set
接口
Set
是一种不包含重复的元素的Collection
,即任意的两个元素e1
和e2
都有e1.equals(e2)=false
,Set
最多有一个null
元素。
很明显,Set
的构造函数有一个约束条件,传入的Collection
参数不能包含重复的元素。
请注意:必须小心操作可变对象(Mutable Object
)。如果一个Set
中的可变元素改变了自身状态导致Object.equals(Object)=true
将导致一些问题。
Map
接口
请注意,Map
没有继承Collection
接口,Map
提供key
到value
的映射。一个Map
中不能包含相同的key
,每个key
只能映射一个 value
。Map
接口提供3
种集合的视图,Map
的内容可以被当作一组key
集合,一组value
集合,或者一组key-value
映射。
Hashtable
类
Hashtable
继承Map
接口,实现一个key-value
映射的哈希表。任何非空(non-null
)的对象都可作为key
或者value
。
添加数据使用put(key, value)
,取出数据使用get(key)
,这两个基本操作的时间开销为常数。
Hashtable
通过initial capacity
和load factor
两个参数调整性能。通常缺省的load factor 0.75
较好地实现了时间和空间的均衡。增大load factor
可以节省空间但相应的查找时间将增大,这会影响像get
和put
这样的操作。
使用Hashtable
的简单示例如下,将1
,2
,3
放到Hashtable
中,他们的key
分别是”one”
,”two”
,”three”
:
Hashtable numbers = new Hashtable();
numbers.put(“one”, new Integer(1));
numbers.put(“two”, new Integer(2));
numbers.put(“three”, new Integer(3));
要取出一个数,比如2
,用相应的key
:
Integer n = (Integer)numbers.get(“two”);
System.out.println(“two = ” + n);
由于作为key
的对象将通过计算其散列函数来确定与之对应的value
的位置,因此任何作为key
的对象都必须实现hashCode
和equals
方法。hashCode
和equals
方法继承自根类Object
,如果你用自定义的类当作key
的话,要相当小心,按照散列函数的定义,如果两个对象相同,即obj1.equals(obj2)=true
,则它们的hashCode
必须相同,但如果两个对象不同,则它们的hashCode
不一定不同,如果两个不同对象的hashCode
相同,这种现象称为冲突,冲突会导致操作哈希表的时间开销增大,所以尽量定义好的hashCode()
方法,能加快哈希表的操作。
如果相同的对象有不同的hashCode
,对哈希表的操作会出现意想不到的结果(期待的get
方法返回null
),要避免这种问题,只需要牢记一条:要同时复写equals
方法和hashCode
方法,而不要只写其中一个。
Hashtable
是同步的。
HashMap
类
HashMap
和Hashtable
类似,不同之处在于HashMap
是非同步的,并且允许null
,即null value
和null key
。,但是将HashMap
视为Collection
时(values()
方法可返回Collection
),其迭代子操作时间开销和HashMap
的容量成比例。因此,如果迭代操作的性能相当重要的话,不要将HashMap
的初始化容量设得过高,或者load factor
过低。
WeakHashMap
类
WeakHashMap
是一种改进的HashMap
,它对key
实行“
弱引用”
,如果一个key
不再被外部所引用,那么该key
可以被GC
回收。
总结
如果涉及到堆栈,队列等操作,应该考虑用List
,对于需要快速插入,删除元素,应该使用LinkedList
,如果需要快速随机访问元素,应该使用ArrayList
。
如果程序在单线程环境中,或者访问仅仅在一个线程中进行,考虑非同步的类,其效率较高,如果多个线程可能同时操作一个类,应该使用同步的类。
要特别注意对哈希表的操作,作为key
的对象要正确复写equals
和hashCode
方法。
尽量返回接口而非实际的类型,如返回List
而非ArrayList
,这样如果以后需要将ArrayList
换成LinkedList
时,客户端代码不用改变。这就是针对抽象编程。
相关文章推荐
- 五、java容器:list、set、map
- JAVA,List,Map,Set,容器
- java中容器介绍(List,Set,Map)
- Java数组与容器类分析资料–数组、List和Set、Map等
- Java的容器 List、Set、Map的区别
- Java中容器[Collection(List,Set,Queue),Map],迭代器(Iterator)和比较器(Comparator)及列表排序
- 深入Java源码解析容器类List、Set、Map
- Java中的容器类List、Set、Map的对比
- Java数组与容器类分析资料--数组、List和Set、Map
- JAVA的容器---List,Map,Set
- Java数组与容器类分析资料–数组、List和Set、Map等
- Java容器(List、Map、Set、Iterator)
- Java编程的逻辑 (75) - 并发容器 - 基于SkipList的Map和Set
- JAVA的容器---List Map Set
- 对象容器 - Java对数据结构的封装 - List, ArrayList, LinkedList, Set, SortedSet, HashSet, Map, TreeMap
- JAVA基础--容器 Set, List, Map
- java中三种容器接口List .Set .Map 及其java容器总结
- JAVA,List,Map,Set,容器
- Java数组与容器类分析资料--数组、List和Set、Map-asp.net关注
- 对象容器 - Java对数据结构的封装 - List, ArrayList, LinkedList, Set, SortedSet, HashSet, Map, TreeMap