Java实用类与机制详解
1. BitSet类
1.1 概述
BitSet类可用于创建动态增长的位向量。实际上,位集是一个从0到
Integer.MAX_VALUE
索引的布尔位向量,初始时所有位都为
false
。这些位可以单独设置、清除或检索。BitSet仅使用足够的存储空间来保存已设置的最高索引位,超出该索引的位被视为
false
。
1.2 构造函数
| 构造函数 | 描述 |
|---|---|
public BitSet(int size)
|
创建一个新的位集,具有足够的初始存储空间,可显式表示从0到
size - 1
的位,所有位初始为
false
。
|
public BitSet()
|
创建一个具有默认初始存储空间的新位集,所有位初始为
false
。
|
1.3 位操作方法
-
单个位操作 :
-
public void set(int index):将指定索引的位设置为true。 -
public void clear(int index):将指定索引的位设置为false。 -
public void flip(int index):将指定索引的位设置为其当前值的补码,即true变为false,false变为true。 -
public boolean get(int index):返回指定索引的位的值。
-
-
范围位操作 :上述方法都有处理位范围的重载形式,这些重载方法接受一个起始索引和一个结束索引,对该范围内的所有位进行设置、清除、翻转或返回操作。
1.4 逻辑操作方法
| 方法 | 描述 |
|---|---|
public void and(BitSet other)
| 对当前位集和另一个位集进行逻辑与操作,并将结果存储在当前位集中。 |
public void andNot(BitSet other)
| 清除当前位集中在另一个位集中被设置的所有位。 |
public void or(BitSet other)
| 对当前位集和另一个位集进行逻辑或操作,并将结果存储在当前位集中。 |
public void xor(BitSet other)
| 对当前位集和另一个位集进行逻辑异或操作,并将结果存储在当前位集中。 |
1.5 示例代码
public class WhichChars {
private BitSet used = new BitSet();
public WhichChars(String str) {
for (int i = 0; i < str.length(); i++)
used.set(str.charAt(i)); // set bit for char
}
public String toString() {
String desc = "[";
for (int i = used.nextSetBit(0);
i >= 0;
i = used.nextSetBit(i+1) ) {
desc += (char) i;
}
return desc + "]";
}
}
使用示例:
public class Main {
public static void main(String[] args) {
WhichChars wc = new WhichChars("Testing123");
System.out.println(wc); // 输出: [ 123Teginst]
}
}
1.6 流程图
graph TD;
A[创建WhichChars对象] --> B[遍历字符串];
B --> C[设置对应位为true];
C --> D[生成字符串表示];
D --> E[输出结果];
2. Observer/Observable机制
2.1 概述
Observer/Observable类型为任意数量的Observer对象提供了一个协议,用于监视任意数量的Observable对象的更改和事件。Observable对象继承自
Observable
类,该类提供了维护一个Observer对象列表的方法,这些Observer对象希望了解Observable对象的更改。所有在“感兴趣”列表中的对象都必须实现
Observer
接口。
2.2 Observer接口
Observer
接口只包含一个方法:
public void update(Observable obj, Object arg)
当Observable对象
obj
有更改或事件要报告时,会调用此方法。
arg
参数用于传递一个任意对象,以向观察者描述更改或事件。
2.3 Observable类方法
| 方法 | 描述 |
|---|---|
protected void setChanged()
|
标记此对象已更改,
hasChanged
方法现在将返回
true
,但不通知观察者。
|
protected void clearChanged()
|
表示此对象不再更改或已通知所有观察者最后一次更改,
hasChanged
方法现在将返回
false
。
|
public boolean hasChanged()
| 返回“更改”标志的当前值。 |
public void notifyObservers(Object arg)
| 通知所有观察者发生了某些事情,然后清除“更改”标志。 |
public void notifyObservers()
|
等同于
notifyObservers(null)
。
|
public void addObserver(Observer o)
|
将观察者
o
添加到观察者列表中(如果它不在列表中)。
|
public void deleteObserver(Observer o)
|
从观察者列表中删除观察者
o
。
|
public void deleteObservers()
| 删除观察者列表中的所有观察者。 |
public int countObservers()
| 返回观察者列表中的观察者数量。 |
2.4 示例代码
import java.util.*;
// 定义Observable类
public class Users extends Observable {
private Map<String, UserState> loggedIn =
new HashMap<String, UserState>();
public void login(String name, String password)
throws BadUserException
{
if (!passwordValid(name, password))
throw new BadUserException(name);
UserState state = new UserState(name);
loggedIn.put(name, state);
setChanged();
notifyObservers(state);
}
public void logout(UserState state) {
loggedIn.remove(state.name());
setChanged();
notifyObservers(state);
}
// ...
}
// 定义Observer类
public class Eye implements Observer {
Users watching;
public Eye(Users users) {
watching = users;
watching.addObserver(this);
}
public void update(Observable users, Object whichState)
{
if (users != watching)
throw new IllegalArgumentException();
UserState state = (UserState) whichState;
if (watching.loggedIn(state)) // user logged in
addUser(state); // add to my list
else
removeUser(state); // remove from list
}
// ...
}
2.5 流程图
graph TD;
A[用户登录/注销] --> B[Users对象设置更改标志];
B --> C[Users对象通知观察者];
C --> D[Eye对象调用update方法];
D --> E[根据用户状态更新显示];
3. Random类
3.1 概述
Random类用于创建管理独立伪随机数序列的对象。如果不关心序列的具体内容,并且希望将其作为双精度值序列,可以使用
java.lang.Math.random
方法。
3.2 构造函数
| 构造函数 | 描述 |
|---|---|
public Random()
| 创建一个新的随机数生成器,其种子将根据当前时间初始化。 |
public Random(long seed)
| 使用指定的种子创建一个新的随机数生成器,具有相同初始种子的两个Random对象将返回相同的伪随机数序列。 |
3.3 常用方法
| 方法 | 描述 |
|---|---|
public boolean nextBoolean()
| 返回一个均匀分布的伪随机布尔值。 |
public int nextInt()
|
返回一个在
Integer.MIN_VALUE
和
Integer.MAX_VALUE
之间均匀分布的伪随机整数值。
|
public int nextInt(int ceiling)
|
返回一个至少为零且小于
ceiling
的伪随机整数值。
|
public long nextLong()
|
返回一个在
Long.MIN_VALUE
和
Long.MAX_VALUE
之间均匀分布的伪随机长整数值。
|
public void nextBytes(byte[] buf)
|
用随机字节填充数组
buf
。
|
public float nextFloat()
| 返回一个在0.0f(包含)和1.0f(不包含)之间均匀分布的伪随机浮点值。 |
public double nextDouble()
| 返回一个在0.0(包含)和1.0(不包含)之间均匀分布的伪随机双精度值。 |
public double nextGaussian()
| 返回一个均值为0.0,标准差为1.0的高斯分布伪随机双精度值。 |
3.4 示例代码
import java.util.Random;
public class RandomExample {
public static void main(String[] args) {
Random random = new Random();
int randomInt = random.nextInt(10); // 生成0到9之间的随机整数
double randomDouble = random.nextDouble(); // 生成0到1之间的随机双精度数
System.out.println("Random int: " + randomInt);
System.out.println("Random double: " + randomDouble);
}
}
3.5 流程图
graph TD;
A[创建Random对象] --> B[调用随机数生成方法];
B --> C[获取随机数];
C --> D[输出随机数];
4. Scanner类
4.1 概述
Scanner类可帮助读取格式化数据文件,它使用正则表达式定位所需数据,并使用解析器将其转换为已知类型。例如,它能使用本地化数字解析来读取人类可能输入的值。
4.2 使用方法
Scanner类有两种主要使用方法,且可以根据需要合理混合使用:
-
读取值流
:直接要求Scanner返回流中的下一个值。
-
面向行读取
:逐行处理输入。
4.2.1 读取值流
以下是一个使用Scanner读取值流的示例代码:
static double sumStream(Readable source) throws IOException {
Scanner in = new Scanner(source);
double result = 0.0;
while (in.hasNext()) {
if (in.hasNextDouble())
result += in.nextDouble();
else
in.next();
}
IOException ex = in.ioException();
if (ex != null)
throw ex;
return result;
}
操作步骤如下:
1. 创建Scanner对象并传入可读源。
2. 初始化结果变量。
3. 使用
hasNext()
方法检查是否还有下一个标记。
4. 使用
hasNextDouble()
方法检查下一个标记是否为双精度值,如果是则读取并累加。
5. 若不是双精度值,则使用
next()
方法读取并忽略。
6. 检查是否有
IOException
,若有则抛出。
7. 返回结果。
Scanner还支持扫描值到
java.math.BigInteger
和
java.math.BigDecimal
对象。同时,它的许多方法可以接受一个模式来指示如何匹配输入,有字符串和
java.util.regex.Pattern
两种重载形式。
4.2.2 面向行读取
以下是一个面向行读取逗号分隔值(CSV)表格的示例代码:
static final int CELLS = 4;
public static List<String[]> readCSVTable(Readable source)
throws IOException {
Scanner in = new Scanner(source);
List<String[]> vals = new ArrayList<String[]>();
String exp = "^(.*),(.*),(.*),(.*)";
Pattern pat = Pattern.compile(exp, Pattern.MULTILINE);
while (in.hasNextLine()) {
String line = in.findInLine(pat);
if (line != null) {
String[] cells = new String[CELLS];
MatchResult match = in.match();
for (int i = 0; i < CELLS; i++)
cells[i] = match.group(i+1);
vals.add(cells);
in.nextLine(); // skip newline
}
else {
throw new IOException("input format error");
}
}
IOException ex = in.ioException();
if (ex!= null)
throw ex;
return vals;
}
操作步骤如下:
1. 创建Scanner对象并传入可读源。
2. 初始化存储结果的列表。
3. 编译正则表达式模式。
4. 使用
hasNextLine()
方法检查是否还有下一行。
5. 使用
findInLine()
方法查找匹配的行。
6. 若找到匹配行,使用
match()
方法获取匹配结果,并提取每个单元格的值。
7. 将提取的单元格值添加到结果列表中,并使用
nextLine()
方法跳过换行符。
8. 若未找到匹配行,抛出
IOException
。
9. 检查是否有
IOException
,若有则抛出。
10. 返回结果列表。
4.3 Scanner与StreamTokenizer对比
Scanner和StreamTokenizer在功能上有一些重叠,但操作模式不同:
| 对比项 | Scanner | StreamTokenizer |
| — | — | — |
| 匹配基础 | 正则表达式 | 字符类 |
| 灵活性 | 可根据正则表达式匹配标记,但处理某些简单任务可能较困难 | 基本逐字符处理输入,可控制字符类,但灵活性不如Scanner |
| 处理注释 | 需要显式处理,较复杂 | 内置处理注释行的能力 |
| 处理CSV文件 | 更改分隔符较简单 | 需要仔细操作字符类,概念上较奇怪 |
| 处理灵活格式文件 | 处理灵活格式较困难 | 适合处理自由格式文件 |
4.4 示例代码
以下是一个处理注释的示例代码:
Scanner in = new Scanner(source);
Pattern COMMENT = Pattern.compile("#.*");
String comment;
// ...
while (in.hasNext()) {
if (in.hasNext(COMMENT)) {
comment = in.findWithinHorizon(COMMENT, 0);
in.nextLine();
}
else {
// process other tokens
}
}
操作步骤如下:
1. 创建Scanner对象并传入可读源。
2. 编译注释正则表达式模式。
3. 使用
hasNext()
方法检查是否还有下一个标记。
4. 使用
hasNext(COMMENT)
方法检查下一个标记是否为注释。
5. 若为注释,使用
findWithinHorizon()
方法查找并跳过注释,然后使用
nextLine()
方法跳过换行符。
6. 若不是注释,处理其他标记。
4.5 流程图
graph TD;
A[创建Scanner对象] --> B[选择读取方式];
B --> C{读取值流?};
C -- 是 --> D[读取下一个值];
D --> E{是否为所需类型?};
E -- 是 --> F[处理值];
E -- 否 --> D;
C -- 否 --> G[读取下一行];
G --> H{是否匹配模式?};
H -- 是 --> I[处理匹配行];
H -- 否 --> J[抛出异常];
F --> K{还有下一个值?};
K -- 是 --> D;
K -- 否 --> L[结束读取];
I --> M{还有下一行?};
M -- 是 --> G;
M -- 否 --> L;
4.6 本地化支持
Scanner类默认在当前区域设置下工作,但可以使用
useLocale()
方法更改区域设置,并使用
locale()
方法获取当前使用的区域设置。类型特定的数字扫描方法(如
hasNextDouble
和
nextInt
)支持本地化,能识别特定区域设置的数字格式。
5. 总结
本文详细介绍了Java中的BitSet、Observer/Observable、Random和Scanner等实用类和机制。BitSet类用于处理位向量,可进行位操作和逻辑操作;Observer/Observable机制提供了一种观察者模式,用于监视对象的更改和事件;Random类用于生成伪随机数;Scanner类可帮助读取格式化数据文件,支持多种使用方法和本地化。通过学习这些类和机制,可以提高Java编程的效率和灵活性。在实际应用中,应根据具体需求选择合适的类和方法,并注意处理可能出现的异常。
Java实用类与机制详细解析
超级会员免费看
1395

被折叠的 条评论
为什么被折叠?



