Java集合框架使用总结

前言:

本文是对Java集合框架做了一个概括性的解说,目的是对Java集合框架体系有个总体认识,如果你想学习具体的接口和类的使用方法,请参看Java API文档。

一、概述

数据结构对程序设计有着深远的影响,在面向过程的C语言中,数据库结构用struct来描述,而在面向对象的编程中,数据结构是用类来描述的,并且包含有对该数据结构操作的方法。

在Java语言中,Java语言的设计者对常用的数据结构和算法做了一些规范(接口)和实现(具体实现接口的类)。所有抽象出来的数据结构和操作(算法)统称为Java集合框架(Java Collection Framework)。

Java程序员在具体应用时,不必考虑数据结构和算法实现细节,只需要用这些类创建出来一些对象,然后直接应用就可以了。这样就大大提高了编程效率。

二、集合框架的层次结构

Collection是集合接口

        |————Set子接口:无序,不允许重复。

        |————List子接口:有序,可以有重复元素。

区别:Collections是集合类

Set和List对比:

Set:检索元素效率低下,删除和插入效率高,插入和删除不会引起元素位置改变。

List:和数组类似,List可以动态增长,查找元素效率高,插入删除元素效率低,因为会引起其他元素位置改变。

Set和List具体子类:

Set

 |————HashSet:以哈希表的形式存放元素,插入删除速度很快。

List

 |————ArrayList:动态数组

 |————LinkedList:链表、队列、堆栈。

Array和java.util.Vector

Vector是一种老的动态数组,是线程同步的,效率很低,一般不赞成使用。

三、Iterator迭代器(接口)

Iterator是获取集合中元素的过程,实际上帮助获取集合中的元素。

迭代器代替了 Java Collections Framework 中的 Enumeration。迭代器与枚举有两点不同:

迭代器允许调用方利用定义良好的语义在迭代期间从迭代器所指向的集合移除元素。

方法名称得到了改进。

Iterator仅有一个子接口ListIterator,是列表迭代器,允许程序员按任一方向遍历列表、迭代期间修改列表,并获得迭代器在列表中的当前位置。ListIterator 没有当前元素;它的光标位置 始终位于调用 previous() 所返回的元素和调用 next() 所返回的元素之间。在长度为 n 的列表中,有 n+1 个有效的索引值,从 0 到 n(包含)。

四、集合框架之外的Map接口

Map将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射一个值。

Map接口是Dictionary(字典)抽象类的替代品。

Map 接口提供三种collection 视图,允许以键集、值集合或键-值映射关系集的形式查看某个映射的内容。映射的顺序 定义为迭代器在映射的 collection 视图中返回其元素的顺序。某些映射实现可明确保证其顺序,如 TreeMap 类;某些映射实现则不保证顺序,如 HashMap 类。

有两个常见的已实现的子类:

HashMap:基于哈希表的 Map 接口的实现。此实现提供所有可选的映射操作,并允许使用 null 值和 null 键。(除了不同步和允许使用 null 之外,HashMap 类与 Hashtable 大致相同。)此类不保证映射的顺序,特别是它不保证该顺序恒久不变。

TreeMap:它实现SortedMap 接口的基于红黑树的实现。此类保证了映射按照升序顺序排列关键字,根据使用的构造方法不同,可能会按照键的类的自然顺序 进行排序(参见 Comparable),或者按照创建时所提供的比较器进行排序。

Hashtable:此类实现一个哈希表,该哈希表将键映射到相应的值。任何非 null 对象都可以用作键或值。

五、线程安全类

在集合框架中,有些类是线程安全的,这些都是JDK1.1中的出现的。在JDK1.2之后,就出现许许多多非线程安全的类。

下面是这些线程安全的同步的类:

Vector:就比ArrayList多了个同步化机制(线程安全)。

Statck:堆栈类,先进后出。

Hashtable:就比HashMap多了个线程安全。

Enumeration:枚举,相当于迭代器。

除了这些之外,其他的都是非线程安全的类和接口。

线程安全的类其方法是同步的,每次只能一个访问。是重量级对象,效率较低。对于非线程安全的类和接口,在多线程中需要程序员自己处理线程安全问题。

六、其他一些接口和类介绍

Dictionary和Hashtable类:

Dictionary提供键值映射的功能,是个抽象类。一般使用它的子类HashTable类。遍历Hashtable类要用到枚举。

Properties类

Properties 继承于 Hashtable,Properties 类表示了一个持久的属性集。Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。一般可以通过读取properties配置文件来填充Properties对象。

参考文档:

java api 文档

注意事项

Java集合框架使用注意事项(一, List)

List的有用实现

1.ArrayList

2.LinkedList

3.Vector

4.Stack

讨论1:底层机制(牵扯到的数据结构的知识请读者自行复习)

ArrayList与Vector都是基于数组实现的,这就说明ArrayList与Vector适合做遍历而不适合做频繁的插入和删除。

LinkedList是基于链表实现的,所以它生来就是为了频繁插入与删除对象。

讨论2:特殊功能

Stack是一个后进先出(LIFO)对象堆栈,而LinkedList除可以被用作堆栈外,还可以被用作队列或双端队列。

不同的是Stack继承自Vector,也就是说它也是基于数组实现的。

讨论3:内存占用

基于数组实现的List,在动态扩展时会产生新的数组,然后把旧数组里的内容复制到新数组里,

这会产生大量的不再被使用的对象引用变量等待系统回收。而基于链表实现的List就不会有这种问题。

讨论4:同步问题

Vector与Stack生来就是同步的,而ArrayList与LinkedList需要使用Collections.synchronizedList(List list)方法来转换成同步List。

从它们的对象上返回的迭代器是快速失败的,也就是说在使用迭代器进行迭代的时候,必须使用迭代器本身的remove、add、set

方法来添加或更改List元素,如果在迭代的同时,在其他线程中

从结构上修改了List(结构上的修改是指任何添加或删除一个或多个元素的操作,或者显式调整底层数组的大小;仅仅设置元素的值不是结构上的修改),快速失败迭代器会尽最大努力抛出ConcurrentModificationException。

讨论5:使用策略

如果数据被从数据源提取,数据量不确定,该数据一经被提取后就几乎不会再添加或删除,那么应该建立一个LinkedList来保存从数据源中取出的数据,然后将该LinkedList转换成ArrayList来优化遍历操作。反过来,数据量确定的数据从数据源取出可以先建立一个ArrayList来保存,根据需要如需频繁增删,就转换为LinkedList,如频繁遍历就不需转换。

转换的方法就是使用对应的List类来封装目标List对象。如

ArrayList al = new ArrayList(); 
 
LinkedList ll = new LinkedList(al);

同理反过来也可以

LinkedList ll = new LinkedList(); 
 
ArrayList al = new ArrayList(ll);

讨论6:toArray()方法

基于数组实现的List会直接返回一个底层数组的拷贝(使用了System.arraycopy方法),基于链表实现的List会新生成一个数组。

讨论7:不可修改

通过使用Collections.unmodifiableList(List list)来生成一个不可修改的List,试图修改返回的列表,不管是直接修改还是通过其迭代器进行修改,都将导致抛出UnsupportedOperationException。

讨论8:遍历器

请尽量使用Iterator,Enumeration已不被鼓励使用。

最后,请参考java.util.Collections类,该类提供了很多有用的操纵集合对象的方法。

 

Java集合框架使用注意事项(二,Map)

Map接口常用的实现类有:

1.HashMap

2.Hashtable

3.TreeMap

4.LinkedHashMap

讨论1:底层机制

HashMap与Hashtable基于数组实现,TreeMap基于树型结构,底层存储结构是典型的链表结构。LinkedHashMap继承自HashMap,所以也是基于数组实现的。

讨论2:继承关系

HashMap与TreeMap继承自AbstractMap,Hashtable继承自Dictionary,LinkedHashMap继承自HashMap。

讨论3:同步关系

Hashtable是同步的,而HashMap与TreeMap以及LinkedHashMap不是同步的,可以使用Collections中提供的方法转换为同步的。

讨论4:迭代器

迭代器都是快速失败的(注:参考本系列第一篇List篇)

讨论5:不可修改

通过使用Collections.unmodifiableMap(Map map)来转换