Java核心技术卷I:基础知识(原书第8版):13.5 遗留的集合
来源:互联网 发布:黑苹果windows双系统 编辑:程序博客网 时间:2024/06/06 19:40
铁文整理
13.5 遗留的集合
本节将讨论Java程序设计语言自问世以来就存在的集合类;Hashtable类和非常有用的子类Properties、Vector的子类Stack以及BitSet类。
13.5.1 Hashtable类
Hashtable类与HashMap类的作用一样,实际上,它们拥有相同的接口。与Vector类的方法一样。Hashtable的方法也是同步的。如果对同步性或与遗留代码的兼容性没有任何要求,就应该使用HashMap。
注释:这个类的名字是Hashtable,带有一个小写的t。在Windows操作系统下,如果使用HashTable会看到一个很奇怪的错误信息,这是因为Windows文件系统对大小写不敏感,而Java编译器却对大小写敏惑。
13.5.2 枚举
遗留集合使用Enumeration接口对元素序列进行遍历。Enumeration接口有两个方法,即hasMoreElements和nextElement。这两个方法与Iterator接口的hasNext方法和next方法十分类似。
例如,Hashtable类的elements方法将产生一个用于描述表中各个枚举值的对象:
Enumeration<Employee> e = staff.elements();
while (e.hasMoreElements()) {
Enployee employee = e.nextElenent();
}
有时还会遇到遗留的方法,其参数是枚举类型的。静态方法Collections.enumeration将产生一个枚举对象,枚举集合中的元素,例如:
List<InputStream> streams = null;
SequenceInputStream in = new SequenceInputStream(CollectTons.enumeration(streams));
// the SequenceInputStream constructor expects an enumeration
注释:在C++中,用迭代器作为参数十分普。遍幸好,在Java的编程平台中,只有极少的程序员沿用这种习惯。传递集合要比传递迭代器更为明智。集合对象的用途更大。当接受方如果需要时,总是可以从集合中获得迭代器,而且,还可以随时地使用集合的所有方法。不过,可能会在某些遗留代码中发现枚举接口,因为这是在Java SE 1.2的集合框架出现之前,它们是泛型集合唯一可以使用的机制。
API:java.util.Enumeration<E> 1.0
boolean hasMoreElements()
E nextElement():返回被检测的下一个元素。如果hasMoreElements返回false,则不要调用这个方法。
API:java.util.Hashtable<K, V> 1.0
Enumeration<K> keys():返回一个遍历散列表中键的枚举对象。
Enumeration<V> elements():返回一个遍历散列表中元素的枚举对象。
API:java.util.Vector<E> 1.0
Enumeration<E> elements():返回遍历向量中元素的枚举对象。
13.5.3 属性映射表
属性映射表(properties map)是一个类型非常恃殊的映射表结构。它有下面3个特性:
键与值都是字符串。
表可以保存到一个文件中,也可以从文件中加载。
使用一个默认的辅助表。
实现属性映射表的Java平台类称为Properties。属性映射表通常用于程序的特殊配置选项,参见第10章。
API:java.util.Properties 1.0
Properties()
Properties(Properties defaults):创建一个带有一组默认值的空的属性映射表。
String getProperty(String key):获得属性的对应关系,返回与键对应的字符串。如果在映射表中不存在,返回默认表中与这个键对应的字符串。
String getProperty(String key, String defaultValue):获得在键没有找到时具有的默认值属性,它将返回与键对应的字符串,如果在映射表中不存在,就返回默认的字符串。
void load(InputStream in):从InputStream加载属性映射表。
void store(OutputStream out, String commentString):把属性映射表存储到OutputStream。
13.5.4 栈
从1.0版开始,标准类库中就包含了Stack类,其中有大家熟悉的push方法和pop方法。但是,Stack类扩展为Vector类,从理论角度看,Vector类并不太令人满意,它可以让栈使用不属于栈操作的insert和remove方法,即可以在任何地方进行插入或刪除操作,而不仅仅是在栈顶。
API:java.util.Stack<E> 1.0
E push(E item)
E pop():弹出并返回栈顶的item。如果栈为空,请不要调用这个方法。
E peek():返回栈顶元素,但不弹出。如果栈为空,请不要调用这个方法。
13.5.5 位集
Java平台的BitSet类用于存放一个位序列(它不是数学上的集,称为位向量或位数组更为合适)。如果需要高效地存储位序列(例如,标志)就可以使用位集。由于位集将位包装在字节里,所以,使用位集要比使用Boolean对象的ArrayList更加高效。
BitSet类提供了一个便于读取、设置或清除各个位的接口。使用这个接口可以避免屏蔽和其他麻烦的位操作。如果将这些位存储在int或long变量中就必须进行这些繁琐的操作。
例如,对于一个名为bucketOfBits的BitSet,
bucketOfBits.get(i)
如果第i位处于“开”状态,就返回true;否则返回false。同样地,
bucketOfBits.set(i)
将第i位置为“开”状态。最后,
bucKetOfBfts.clear(i)
将第i位置为“关”状态。
C++注释:C++位集糢板与Java平台的BitSet功能一样。
API:java.util.BitSet 1.0
BitSet(int initialCapacity):创建一个位集
int length():返回位集的“逻辑长度,即1加上位集的最高设置位的索引。
boolean get(int bit)
void set(int bit)
void clear(int bit)
void and(BitSet set)
void or(BitSet set)
void xor(BttSet set)
void andNot(BitSet set):清除这个位集中对应另一个位集中设置的所有位。
“Eratosthenes筛子”基准测试
作为位集应用的一个示例,这里给出一个采用“Eratosthenes筛子”算法査找素数的实现(素数是指只能被1和本身整除的数,例如2、3或5,“Eratosthenes筛子”算法是最早发现的用来枚举这些基本数字的方法之一)。这并不是一种查找素数的最好方法,但是由于某种原因,它已经成为测试编译程序性能的一种流行的基准。(这也不是一种最好的基准测试方法,它主要用于测试位操作。)
在此,将尊重这个传统,并给出实现。其程序将计算2~2 000 000之间的所有素数(一共有148 933个素数,或许不打算把它们全部打印出来吧)。
这里并不想深入程序的细节,关键是要遍历一个拥有200万个位的位集。首先将所有的位置为“开”状态,然后,将已知素数的倍数所对应的位都置为“关”状态。经过这个操作保留下来的位对应的就是素数。例13-7是用Java程序设计语言实现的这个算法程序,而例13-8是用C++实现的这个算法程序。
注释:尽管筛选并不是一种好的基准测试方法,这里还是对这个算法的两个算法的运行时间进行了测试,下面是在1.66 GHz双核IBM ThinkPad计算机上运行时间的结果,这台计算机内存为2GB,操作系统为Ubuntu 7.04。
C++ (g++ 4.1.2): 360毫秒
Java(Java SE 6):105毫秒
我们已经对《Java核心技术》7个版本进行了这项测试,在最后的3个版本中,Java轻松地战胜了C++。公平地说,如果有人改变C++优化器的级别,将可以用60毫秒的时间战胜Java。如果程序运行的时间长到触发Hotspot即时编译器时,Java只与C++打个平手。
例13-7 Sieve.java
import java.util.*;
/**
* This program runs the Sieve of Erathostenes benchmark. It computes all primes
* up to 2,000,000.
*
* @version 1.21 2004-08-03
* @author Cay Horstmann
*/
public class Sieve {
public static void main(String[] s) {
int n = 2000000;
long start = System.currentTimeMillis();
BitSet b = new BitSet(n + 1);
int count = 0;
int i;
for (i = 2; i <= n; i++)
b.set(i);
i = 2;
while (i * i <= n) {
if (b.get(i)) {
count++;
int k = 2 * i;
while (k <= n) {
b.clear(k);
k += i;
}
}
i++;
}
while (i <= n) {
if (b.get(i))
count++;
i++;
}
long end = System.currentTimeMillis();
System.out.println(count +" primes");
System.out.println((end - start) +" milliseconds");
}
}
例13-8 Sieve.cpp
/**
@version 1.21 2004-08-03
@author Cay Horstmann
*/
#include <bitset>
#include <iostream>
#include <ctime>
using namespace std;
int main()
{
const int N = 2000000;
clock_t cstart = clock();
bitset<N + 1> b;
int count = 0;
int i;
for (i = 2; i <= N; i++)
b.set(i);
i = 2;
while (i * i< = N)
{
if (b.test(i))
{
count++;
int k = 2 * i;
while (k <= N)
{
b.reset(k);
k += i;
}
}
i++;
}
while (i< = N)
{
if (b.test(i))
count++;
i++;
}
clock_t cend = clock();
double millis = 1000.0 * (cend - cstart) / CLOCKS_PER_SEC;
cout << count << " primes\n" << millis <<" milliseconds\n";
return 0;
}
到此为止,Java集合框架的旅程就结束了,正如所看到的,Java类库提供了大量的集合类以适应程序设计的需要。在本书的最后—章,将讨论非常重要的并发程序设计。
- Java核心技术卷I:基础知识(原书第8版):13.5 遗留的集合
- Java核心技术卷I:基础知识(原书第8版):13.2 具体的集合
- Java核心技术卷I:基础知识(原书第8版):14.7 线程安全的集合
- Java核心技术卷I:基础知识(原书第8版):13.1 集合接口
- Java核心技术卷I:基础知识(原书第8版):13.3 集合框架
- 《Java核心技术 卷I:基础知识(原书第8版)》勘误表
- Java核心技术卷I:基础知识(原书第8版):6.1 接口
- Java核心技术卷I:基础知识(原书第8版):6.5 代理
- Java核心技术卷I:基础知识(原书第8版):11.4 断言
- Java核心技术卷I:基础知识(原书第8版):13.4 算法
- Java核心技术卷I:基础知识(原书第8版):14.5 同步
- Java核心技术卷I:基础知识(原书第8版):14.10 同步器
- Java核心技术卷I:基础知识(原书第8版):10.4 应用程序存储的配置
- Java核心技术卷I:基础知识(原书第8版):12.2 简单泛型类的定义
- Java核心技术卷I:基础知识(原书第8版):12.4 类型变量的限定
- 读《JAVA 核心技术》卷I 基础知识(原书第10版)
- Java核心技术卷I:基础知识(原书第8版):5.2.2 相等测试与继承
- Java核心技术卷I:基础知识(原书第8版):6.2 对象克隆
- 集成到web项目之后,导出PDF时,中文无法正常显示或找不到中文字体
- Android 颜色对照表
- Android视图注入库:butterknife
- c语言写坦克大战项目要求
- jquery获取当年月天数以及当月的最后一天|当月的天数
- Java核心技术卷I:基础知识(原书第8版):13.5 遗留的集合
- JAVA环境变量配置
- 富文本编辑器ueditor
- 计算一个项目工程中所有包下面的代码行数
- cocos2dx接入shareSDK
- 十个常用PHP类库整理
- 智能聊天机器人
- Apache HttpClient模拟登录
- NBA球员 ESPN前20排名:詹姆斯再居榜首