文章目录
为了使程序能方使地存储和操纵数门不固定的一组数据,JDK 类库提供了Java集合,所有 Java 集合类都位于
java.util
包中。与 Java 数组不同,Java集合中不能存放基本类型数据,而只能存放对象的引用。Java 集合主要分为4 种类型:
- Set(集):集合中的对象不按特定方式排序,并且没有重复的对象。它的有些实现类能对集合中的对象按特定方式排序。
- List(列表):集合中的对象按照索引位置排序,可以有重复的对象,允许按照对象在集合中的索引位置检索对象。List 与数组有些相似。
- Queue(队列):集合中的对象按照先进先出的规则来排列。在队列的未尾添加元素,在队列的头部删除元素。可以有重复的对象。双向队列则允许在队列的末尾和头部添加和删除元素。
- Map(映射):集合中的每一个元素包含对键(Key)对象和值(Value)对象,集合中没们重复的键对象,值对象可以重复。它的有些实现类能对集合中的键对象进行排序。
15.1 Collection 和 Iterator 接口
在 Collection
接口中声明了适用于Java集合(只包括 Set、List 和 Queue) 的通用方法。
方法 | 描述 |
---|---|
boolean add(Object o) | 向某合中加入-个对象的引用 |
void clear() | 删除集合中的所有对象,即不再持有这些对象的引用 |
boolean contains(Object o) | 判断在集合中是否持特定对象的引用 |
boolean isEmpty() | 判断集合是否为空 |
Iterator iterator() | 返回一个 Iterator 对象 ,可用它来遍历集合中的元素 |
boolean remove(Object o) | 从集合中删除一个对象的引用 |
int size() | 返回集合中元素的数目 |
Object[] toArray() <T> T[] toArray(T[] a) | 返回一个数组,该数组包含集合中的所有元素 |
iterator
接口隐藏底层集合的数据结构,向客户程序提供了遍历各种类型的集合的统一接口。Iterator 接口中声明了如下方法:
方法 | 描述 |
---|---|
boolean hasNext() | 判断集合中的元素是否遍历完毕,如果没有,就返回 true |
E next() | 返回下一个元素 |
void remove() | 从集合中删除由 next()方法返同的当前元素 |
import java.util.*;
public class Visitor {
//如果集合没有排序,Iterator 遍历集合中元素的顺序是任意的,并不一定与加入元素的顺序一致
public static void print(Collection<? extends Object> c) {
Iterator<? extends Object> it = c.iterator();
while (it.hasNext()) {
Object element = it.next();
System.out.println(element);
}
}
//只有实现了 java.lang.Iterable 接口的对象才允许使用 foreach 语句进行遍历
public static void printWithForEach(Collection<? extends Object> c) {
for (Object element : c)
System.out.println(element);
}
public static void main(String[] args) {
Set<String> set = new HashSet<String>();
set.add("Tom");
print(set);
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("Tom", 23);
printWithForEach(map.entrySet());
//map.entrySet()方法返回一个存放了Map.Entry元素集合,每个Map.Entry元素表示一对键值
}
}
当通过 Collection 集合的 Iterator() 方法得到一个 Iterator 对象后 , 如果当前线程或其他线程接着又通过 Collection 集合的一些方法对集合进行了修改操作(调用当前 Iterator 对象的 remove() 方法来修改集合除外),接下来访问这个 Iterator 对象的 next() 方法会导致 Java.util.ConcurrentModificationException
运行时异常
import java.util.*;
public class Concurren Tester{
public static void main(String[] args) {
final int size = 1000;
final Set<Integer> set = new HashSet<Integer>();
for (int i = 0; i < size; i++)
set.add(new Integer(i));
Thread reader = new Thread() {
public void run() {
for (Integer i : set) {
System.out.println(i); //抛出ConcurrentModificationException
yield(); //把CPU让出给别的线程
}
}
}
Thread remover = new Thread() {
public void run() {
for (int i = 0; i < size; i++) {
set.remove(new Integer(i)); //删除集合中元素
yield(); //让出CPU
}
}
}
reader.start();
remover.start();
}
}
Iterator 对象运用了快速失败机制(fail-fast),一旦监测到集合已被修改(有可能是被其他线程修改的),就抛出 ConcurrentModificationException 运行时异常,而不是显示修改后的集合的当前内容,这可以避免潜在的由于共享资源竞争而导致的并发问题。
15.3 Set集
Set 是最简单的一种集合,集合中的对象不按特定方式排序,并且没有重复对象。Set 接口主要有两个实现类:HashSet 和 TreeSet。HashSet
类按照哈希算法来存取集合中的对象,存取速度比较快。HashSet类还有一个子类 LinkedHashSet
类,它不仅实现了哈希算法,而且实现了链表数据结构,链表数据结构能提高插入和删除元素的性能。TreeSet
类实现了 SortedSet 接口,具有排序功能。
HashSet 类按照哈希算法来存取集合中的对象,具有很好的存取和查找性能。当向集合中加入一个对象时,HashSet 会调用对象的 hashCode()
方法获得哈希码,然后根据这个哈希码进一步计算出对象在集合中的存放位置。在 Object
类中定义了 hashCode() 和 equals() 方法,Object 类的 equals() 方法按照内存地址比较对象是否相等,因此如果 object1.equals(object2)
为 true,表明 object1 变量和 object2 变量实际上引用同一个对象,那么 objectl 和 object2 的哈希码也肯定相同。所以如果用户定义的类覆盖了 Object 类 equals() 方法,就必须同时覆盖 Object 类的 hashCode() 方法并且保证两个相等的对象哈希码也一样。
TreeSet 类实现了 SortedSet 接口,能够对集合中的对象进行排序。TreeSet 支待两种排序方式:自然排序和客制化排序,默认情况下 TreeSet 采用自然排序方式。
- 自然排序
- 在 JDK 类库中,有一部分类实现了
Comparable
接口,如 Integer、Double 和 String等。Comparable 接口有一个compareTo(Object o)
方法,它返回整数类型。对于表达式x.compareTo(y)
, 如果返回值为 0, 表示 x=y;如果返回值大于0, 表示 x>y;如果返回值小于0,表示 x<y。Set<Object> set = new TreeSet<Object>(); set.add(new Integer(8)); set.add(new String("9")); //抛出ClasCastException
- 如果用户自定义的类没有实现
Comparable
接口,会在第二次调用TreeSet的add()方法抛出ClasCastException
异常。避免此类异常需要实现该接口并实现compareTo()
方法。public class Customer implements Comparable { private String name; private int age; ... public int compareTo(Object o) { Customer other = (Customer) o; if (this.name.compareTo(other.getName()) > 0) return 1; else if (this.name.compareTo(ohter.getName()) < 0) return -1; if (this.age > other.getAge()) return 1; else if (this.age < other.getAge()) return -1; return 0; } public boolean equals(Object o) { //相等条件为name、age属性相等 if (this == o) return true; if (!(o instanceof Customer)) return false; final Customer other = (Customer) o; if (this.name.equals(other.getName()) && this.age == other.getAge()) return true; else return false; } public int hashCode() { //重写hashCode,保证两对象相等其哈希码也相等 int result; result = (name == null ? 0 : name.hashCode()); result = 29 * result + age; return result; } }
- 在 JDK 类库中,有一部分类实现了
- 客制化排序
- 除了自然排序外,TreeSet 还支持客户化排序。
java.util.Comparator<T>
接口提供具体的排序方式,<T>
指定被比较的对象的类型,Comparator 有compare(T x, T y)
方法,用于比较两个对象的大小。当该方法的返回值等于0,表示 x=y;返回值大于0,表示 x>y;返回值小于0, 表示 x<y。 - 如果希望 TreeSet 按照自定义对象的某个属性进行排序,可以先创建一个实现
Comparator
接口的类,然后构造TreeSet实例时,调用TreeSet(Comparator comparator)
构造方法。import java.util.*; public class CustomerComparator implements Comparator<Customer> { public int compare(Customer c1, Customer c2) { if (c1.getName().compareTo(c2.getName()) > 0) return -1; else if (c1.getName().compareTo(c2.getName()) < 0) return 1; else return 0; } } public static void main(String[] args) { Set<Customer> set = new TreeSet<Customer>(new CustomerComparator()); ... }
- 除了自然排序外,TreeSet 还支持客户化排序。
15.4 List列表
List 的主要特征是其元素以线性方式存储,集合中允许存放重复对象。List 接口主要的实现类包括:
ArrayList
:长度可变的数组。允许对元素进行快速的随机访问,但插入与删除元素的速度较慢。LinkedList
:在实现中采用链表数据结构。对顺序访问进行了优化,插入和删除元素的速度较快,随机访问则相对较慢。单独具有 addfirst()、addLast()、getFirst()、getLast()、removeFirst()和removeLast()方法,这些方法使得它可以作为堆栈、队列和双向队列使用。
访问列表元素
List 中的对象按照索引位置排序,客户桯序可以按照对象在集合中的索引位置来检索对象。List 的 get(int index)
方法返回集合中由参数 index 指定不同索引位置的对象。List 的 iterator()
能返回 Iterator 对象,可以用 Iterator 来遍历集合中的所有对象。
for (int i = 0; i < list.size(); i++) System.out.println(list.get(i));
Iterator<Integer> it = list.iterator();
while (it.hasNext()) System.out.println(it.next());
for (Integer i : list) System.out.println(i);
列表排序
List 只能对集合中的对象按索引位置排序,如果希望对 List 中 的对象按其他特定的方式排序,可以借助 Comparator
接口和 Collections
类 。 Collections 类是 Java 集合类库中的辅助类,它提供了操纵集合的各种静态方法,其中 sort() 方法用于对 List 中的对象进行排序:
sort(List list)
:对 List 中的对象进行自然排序。sort(List list, Comparator comparator)
:对 List 中的对象进行客户化排序,comparator 参数指定排序方式。
ListIterator接口
List 的 lisIterator()
方法返回一个 ListIterator
对象,ListIterator 接口继承了 Iterator
接 口, 此外还提供了专门操纵列表的方法:
add()
:向列表中插入一个元素。hasNext()
:判断列表中是否还有下一个元素。hasPrevious()
:判断列表中是否还有上一个元素。next()
:返回列表中的下一个元素。previous()
:返回列表中的上一个元素。
//向一个排序的 List 列表中按顺序插入数据。
public static void myInsert(List<Integer> list, int data) {
ListIterator<Integer> it = list.listIterator();
while (it.hasNext()) {
Integer in = it.next();
if (data <= in.intValue) {
it.previous();
it.add(data);
break;
}
}
}
获得固定长度的 List 对象
java.util.Arrays
类的 asList()
方法能够把一个 Java 数组包装为一个 List 对象,这个 List 对象代表固定长度的数组。所有对 List 对象的操作都会被作用到底层的 Java 数组。由于数组的长度不能改变,因此不能调用这种 List 对象的 add()和 remove()方法,否则会抛出 java.lang.UnsupportedOperationException
运行时异常:
String[] ss = {"Tom", "Mike", "Jack"};
List<String> list = Arrays.asList(ss); //数组转化为固定长度的List
list.set(0, "Jane"); //合法,修改某个位置的元素
System.out.println(Arrays.toString(ss)); //打印
list.reomve("Mike"); //抛出异常
list.add("Mary"); //抛出异常
15.5 Queue队列
从 JDK5 开始,用 java.util.Queue
接口来表示队列。队列的特点是向末尾添加元素,从队列头部删除元素,队列中允许有重复元素。
- 加入元素方法:
boolean add(E element) boolean offer(E element) //以上两个方法都向队列的末尾添加元素,如果操作成功就返回 true 。参数的类型 E 为泛型类型。 //这两个方法的区别在于,如果队列已满 //add() 方法会抛出 IllegalStateException,而 offer() 方法返回 false。
- 删除元素方法:
E remove() E poll() //以上两个方法都会删除队列头部的元素。 这两个方法的区别在于, //如果队列为空,remove() 方法抛出NoSuchElementException,而 poll() 方法则返回 null。
- 获取元素方法:
E element() E peek() //以上两个方法都会返回队列头部的元素,但不删除它。这两个方法的区别在于, //如果队列为空,element() 方法抛出 NoSuchElementException,而 peek() 方法则返回 null。
Deque双向队列
Queue 接口是单向队列,它有一个子接口 Deque,表示双向队列。双向队列的特点是在队列的头部和末尾都可以添加或删除元素。
-
Deque 接口具有以下向队列头部或末尾添加元素的方法:
void addFirst(E element) void addLast(E element) boolean offerFirst(E element) boolean offerLast(E element) //如果队列已满,前两个方法抛出 IllegalStateException,而后两个方法则返回 false
-
Deque 接口具有以下从队列头部或末尾删除元素的方法:
E removeFirst() E reomveLast() E pollFirst() E pollLast() //如果队列为空,前两个方法抛出 NoSuchElementException,而后两个方法则返回null
-
Deque 接口具有以下从队列头部或末尾获取元素(不会删除该元素)的方法:
E getFirst() E getLast() E peekFirst() E peekLast() //如果队列为空,前两个方法抛出 NoSuchElementException,而后两个方法则返回 null
LinkedList
类和 ArrayDeque
类都实现了 Deque 接口。
PriorityQueue优先队列
PriorityQueue(优先级队列)会按照排序的方式对队列中的元素进行排序和检索。因此加入到 PriorityQueue 中的对象必须实现 Comparable 接口
,提供对元素排序时两个元素之间的比较规则。
值得注意的是,当通过 foreach 语句遍历优先级队列时,获得的元素并没有进行排序,而在通过 remove() 方法删除元素时,该方法总是会删除当前队列中的最小元素。
import java.util.*;
public class PriorityQueueTester {
public static void main(String[] args) {
Queue<Intger> queue = new PriorityQueue<Integer>();
queue.add(3);queue.add(1);queue.add(2);
for (Integer i : queue) System.out.println(i);
while (!queue.isEmpty()) System.out.println(queue.remove());
}
}
//打印结果: 1 3 2 1 2 3
15.6 Map映射
Map(映射)是种把键对象和值对象进行映射的集合,它的每一个元素都包含一对键对象和值对象,而们对象仍可以是 Map 类型,以此类推,这样就形成了多级映射。向 Map 集合中加入元素时,必须提供一对键对象和值对象,从 Map 集合中检索元素时,只要给出键对象,就会返回对应的值对象。
put(Object key, Object value) //向集合中加入元素
get(Object key) //检索与键对应的值对象
Map 集合中的键对象不允许重复,也就是说,任意两个键对象通过 equals() 方法比较的结果都是 false。对于值对象则没有唯一性的要求,可以将任意多个键对象映射到同一个值对象上。
Map 的 entrySet()
方法返回一个 Set 集合,在这个集合中存放了 Map.Entry
类型的元素,每个 Map.Entry 对象代表 Map 中的一个键值对。Map.Entry 对象的 getKey()
方法返回键,getValue()
方法返回值。
Map 有两种比较常用的实现:HashMap 和 Treemap。
- HashMap 按照哈希算法来存取键对象,有很好的存取性能,为了保证 HashMap 能正常工作,和 HashSet 一样,要求当两个键对象通过 equals() 方法比较为 true 时,这两个键对象的 hashCode() 方法返回的哈希码也一样。
- TreeMap 实现了
SortedMap
接口,能对键对象进行排序。和 TreeSet 一样,TreeMap 也支持自然排序和客户化排序两种方式。如果希望 TreeMap 对键对象进行客户化排序,可调用它的另一个构造方法TreeMap(Comparator comparator)
,参数 comparator 指定具体的排序方式。
15.7 HashSet 和 HashMap 的负载因子
HashSet 和 HashMap 都运用哈希算法来存取元素。哈希表中的每个位置也称为 桶(bucket),在发生哈希冲突的时候,在桶中以链表的形式存放多个元素。
HashSet 和 HashMap 都有以下属性:
- 容量 (capacity):哈希表中桶的数量。
- 初始容量(initial capacity):创建 HashSet 和 HashMap 对象时桶的数量。在 HashSet 和 HashMap 的构造方法中允许设置初始容量。
- 大小 (size):元素的数目。
- 负载因子(load factor):等于
size/capacity
。负载因子为0,表示空的哈希表;负载因子为 0.5, 表示半满的哈希表,以此类推。轻负载的哈希表具有冲突少、适合插入和查找的优点(但是用 Iterator 遍历元素的速度较慢)。HashSet 和 HashMap 的构造方法允许指定负载因子,当哈希表的当前负载达到用户设定的负载因子时,HashSet 和 HashMap 会自动成倍地增加容量(即桶的数量),并且重新分配原有的元素的位置。一般默认负载因子为 0.75。
15.8 Collections 集合实用类
之前介绍了 java.util.Arrays
类,它提供了一系列操纵 Java 数组的静态方法。对于 Java 集合,也有 一 个实用类:java.util.Collections
,它的一部分静态方法专门用于操纵 List 类型集合,还有一部分静态方法可用于操纵所有的 Collection 类型或 Map 类型集合。
List 代表长度可变的数组, Collections 的以下方法适用于 List:
copy(List dest, List src)
//把一个 List 中的元素复制到另一个 List 中
fill(List list, Object o)
//向列表中填充元素
sort(List list)
//把 List 中的元素进行自然排序
binarySearch(List list, Object key)
//查找 List 中与给定对象 key 相同的元素。
//在调用该方法时,必须保证 List 中的元素已经自然排序,这样才能得到正确的结果。
binarySearch(List list, Object key, Comparator c)
//查找 List 中与给定对象 key相同的元素,Comparator 类型的参数指定比较规则
//在调用该方法时,必须保证 List 中的元素已经按照 Comparator 类型的参数的比较规则排序
shuffle(List list)
//对 List 中的元素进行随机排列
Collections 的以下方法适用于 Collection 类型或 Map 类型:
Object max(Collection coll)
Object min(Collection coll)
//返回集合中的最大/小元素,采用自然排序的比较规则
Object max(Collection coll, Comparator comp)
Object min(Collection coll, Comparator comp)
//返回集合中的最大/小元素,Comparator 类型的参数指定比较规则
Set singleton(Object obj)
//返回一个不可改变的 Set 集合,它只包含一个参数指定的对象
List singletonList(Object obj)
//返回一个不可改变的 List 集合,它只包含一个参数指定的对象
Map singletMap(Object key, Object value)
//返回一个不可改变的 Map 集合,它只包含参数指定的一对键与值
Collection synchronizedCollection(Collection c)
List synchronizedList(List list)
Map synchronizedMap(Map map)
Set synchronizedSet(Set set)
//在原来集合的基础上,返回支持同步的(即线程安全的)集合。
Collection unmodifiableCollection(Collection c)
List unmodifiableList(List list)
Map unmodifiableMap(Map map)
Set unmodifiableSet(Set set)
//在原来集合的基础上,返回不允许修改的集合视图 。
如果集合中仅仅包含一个元素,并且不允许修改这个集合,那么可以用 Collections 的 singletonXXX()
方法来构造这样的集合。程序不允许对这个集合进行添加或删除操作,否则会导 java.lang.UnsupportedOperationException
运行时异常。
如果集合中的元素不允许修改,可以用 Collections 的 unmodifiableXXX()
方法来获得原始集合的一个集合视图。桯序可以读取集合视图中的内容,但不允许修改它。如果直接对原始集合做了修改,集合视图会反映修改后的集合的内容:
Set<String> originalSet = new HashSet<String>();
originalSet.add("Tom"); originalSet.add("Mike");
Set<String> setView = Collections.unmodifiableSet(originalSet);
originalSet.add("Linda");
System.out.println(Arrays.toString(setView.toArray())); //打印 Tome Mike Linda
setVie.add("Mary"); //抛出UnsupportedOperationException异常
15.9 线程安全的集合
在 Java 集合框架中, Set、List、Queue 和 Map 的实现类都没有采取同步机制。在单线程环境中,这种实现方式会提高操纵集合的效率,Java 虚拟机不必因为管理同步锁而产生额外的开销。但在多线程环境中,可能会有多个线程同时操纵同一个集合,为了避免并发问题,可以采取以下几种解决措施:
- 在程序中对可能导致并发问题的代码块进行同步。
- 利用 Collections 的
synchronizedXXX()
方认获得原始集合的同步版本:Collection synchronizedCollection = Collections.sychronizedCollection(originalCollection);
- 如果集合只包含单个元素并且不允许被修改,可以用 Collections 的
singletonXXX()
方法来构造这样的集合,这可以避免集合被线程错误地修改,而且由于不必采取同步措施,可以提高并发性能。 - 如果集合的元素不允许被修改,可以用 Collections 的
unmodifiableXXX()
方法来生成原始的集合视图,让线程只访问这个集合视图 ,这可以避免集合被线程错误地修改,而且由千不必采取同步措施,可以提高并发性能。 - 用 Collections 的
synchronizedXXX()
方法获得原始集合的同步版本后,如果一个线程操纵集合的同步版本,而另一个线程操纵原始的集合,那么仍然会导致并发问题。为了避免这种悄况,可以直接采用java.util.concurrent
并发包提供的线程安全的集合,例如:ConcurrentHashMap
ConcurrentSkipListMap
ConcurrentSkipListSet
ConcurrentLinkedQueue
。这些集合的底层实现采用了复杂的算法,保证多线程访 问集合时,既能保证线程之间的同步,又具有高效的并发性能。
15.10 集合与数组的互换
集合和数组都用来存放多个元素,它们之间可以通过特定的方式互相转换。
- 把数组转换为集合。
java.util.Arrays
类是一个数组实用类,它的asList()
静态方法能够把数组转换成一个 List 对象
大多数集合都有以下形式的构造方法,该构造方法在创建新集合的时候,会把参数 c 指定的集合中的元素复制到新集合中:Integer[] array = {1,2,3}; List<Intger> list = Array.asList(array);
因此,在通过HashSet(Collection<? extends E> c) TreeSet(Collection<? extends E> c) ArrayList(Collection<? extends E> c) LinkedList(Collection<? extends E> c)
Arrays.asList()
方法得到了 一个 List 对象后,还可以把它转换为其他类型的集合。Integer[] array = {1,2,3}; List<Integer> list = Arrays.asList(array); List<Integer> arrayList = new ArrayList<Integer>(list); Set<Integer> hashSet = new HashSet<Integer>(list);
- 把集合转换为数组
java.util.Collection
接口中定义了toArray()
方法,能把集合转换为数组,它有两种重载形式:Object[] toArray()
返回Object[]
类型数组。<T> T[] toArray(T[] a)
返回泛型标记<T>
指定类型数组。
List<Integer> list = new ArrayList<Integer>(); list.add(1); list.add(2); list.add(3); Object[] arr1 = list.toArray(); //返回Object[]类型数组 Integer[] arr2 = list.toArray(new Integer[0]); //返回Integer[]类型数组 //参数 new lnteger[0] 仅仅用来指定返回数组的类型
15.11 集合的批量操作
如果需要一次处理大批量数据,可以调用集合的支持批量操作的方法。在 Collection 接口中定义了以下方法:
boolean retainAll(Collection<?> c)
//修改当前集合,在当前集合中保留那些同时位于参数 c 集合中的元索,删除其余元素。(求交集)
//如果当前集合最终做了改动,就返回 true 。
boolean removeAll(Collection<?> c)
//删除当前集合中的那些同时位于参数 c 集合中的元素(去交集)
boolean addAll(Collection<? extends E> c)
//把参数 c 集合中的元素加入到当前集合中
boolean containsAll(Collection<?> c)
//判断当前集合中是否存在参数 c 集合中的元素
List<E> subList(int fromIndex, int toIndex)
//在 List 接口中一个用于获得子列表视图的方法(类似substring)
//fromIndex 参数和 toIndex 参数分别指定元素的起始索引和结束索引
//起始索引对应的元素会加入到子列表中,而结束索引对应的元素不会加入到子列表中。
15.12 历史集合类
在早期的 JDK1.0 版本中,代表集合的类只有 Vector
Stack
Enumeration
Hashtable
Properties
和 BitSet
类。直到 JDK1.2 版本开始,才出现了 Collection
Set
List
和 Map
接口,以及各种实现类,它们构成了比较完整的 Java 集合框架, 在 JDK5 版本中,又增加了 Queue
接口及各种实现类。JDK1.0 版本中的集合类也称为历史集合类。
历史集合类 | 描述 | 缺点 | 新集合框架中的替代 |
---|---|---|---|
Vector | 集合中的元素有索引位置,在新的集合框架中改为实现了List接口 | 采用了同步机制,影响操纵集合的性能 | ArrayList LinkedList |
Stack | 堆栈,支持后进先出的操作 | 采用了同步机制,影响操纵集合的性能;Stack继承了Vector类,使得Stack不能作为严格的堆栈,因为其支持随机访问 | LinkedList |
Hashtable | 集合中的每个元素包含一个键值对。在新框架内改为实现了Map接口。 | 采用了同步机制,影响操纵集合的性能 | HashMap |
Properties | 集合中的每个元素包含一个键值对。继承了Hashtable | 采用了同步机制,影响操纵集合的性能 | 无 |
Enumeration | 用于遍历集合中的元素 | 只能与Vector和Hashtable等历史集合配套 | Iterator |
BitSet | 存放一组 boolean 类型数据,支持与、或、异或等操作 | 无 | 无 |
15.13 枚举类型
为了提高代码的可重用性,从 JDK5 开始,提供了抽象的 Java.lang.Enum
枚举类,它的声明如下:
public abstract class Enum<E extends Enum<E>>
Enum类是抽象类,<E extends Enum<E>>
为泛型标记,表示 Enum 类拥有的静态常量实例也是 Enum 类型或者其子类型。用户自定义的枚举类只需继承 Enum 类就行了。例如 Gender 枚举类可以继承 Enum 类:
public class Gender extends Enum {
public static final Gender FEMALE;
public static final Gender MALE;
...
}
//为了进一步简化编程,JDK5 提供了专门用千声明枚举类型的关键字 enum , 以上程序代码等价于:
public enum Gender{FEMALE, MALE}
Enum 类具有以下非抽象的方法:
int compareTo(E o)
//比较当前枚举常堂与指定对象的顺序
Class<E> getDeclaringClass()
//返回表示当前枚举常量的枚举类型的 Class 对象
String name()
//返回当前枚举常量的名称
int ordinal()
//返回当前枚举常量 的序数,即它在枚举声明中的位置 ,其中初始枚举常量的序数为零
String toString()
//返回枚举常量的名称
static <T extends Enum<T>> T valueOf(Class<T> enumType, String name)
//根据指定的枚举类型和名称返回相应的枚举常量实例
static Enum[] value()
//以数组的形式返回该枚举类型的所有枚举常擞实例。
在自定义的枚举类中也可以定义构造方法和属性 。 这个构造方法必须是 private 类型的。
public class GenderNewTest {
enum Gender{
FELMAL("famle"),
MALE("male");
private String description;
private Gender(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
}
}
在 Java API 中,还为 Enum 类提供了两个适配器:
java.util.EnumSet
类:把枚举类型转换为集合类型。它的静态的allOf()
方法能把枚举类的所有常量实例存放到一个 EnumSet 类型的集合中,然后返回这个集合。Java.util.EnumMap
类:把枚举类型转换为映射类型。它的EnumMap(Class<K> keyType)
构造方法用来指定具体的枚举类型。枚举常量以 Key 的形式存放在 Map 中。
import java.util.*;
public class ColorTester {
enum Color{RED,BULE,YELLOW,GREEN}
public static void main(String[] args) {
/* EnumSet */
EnumSet<Color> colorSet = EnumSet.allOf(Color.class);
for (Color c : colorSet) System.out.println(c);
/* EnumMap */
EnumMap<Color, String> colorMap = new EnumMap<Color, String>(Color.class);
ColorMap.put(Color.RED,"red");
...
Set<Map.Entry<Color, String>> set = colorMap.entrySet();
for (Map.Entry entry : set) System.out.println(entry.getKey() + " " + entry.getValue());
}
}