友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
Java编程思想第4版[中文版](PDF格式)-第65部分
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!
有关的还有一个重要的警告:若在执行一次binarySearch()之前不调用 sort(),便会发生不可预测的行为,
其中甚至包括无限循环。
对String 的排序以及搜索是相似的,但在运行程序的时候,我们会注意到一个有趣的现象:排序遵守的是字
典顺序,亦即大写字母在字符集中位于小写字母的前面。因此,所有大写字母都位于列表的最前面,后面再
跟上小写字母——Z 居然位于a 的前面。似乎连电话簿也是这样排序的。
2。 可比较与比较器
但假若我们不满足这一排序方式,又该如何处理呢?例如本书后面的索引,如果必须对以A 或a 开头的词条
分别到两处地方查看,那么肯定会使读者颇不耐烦。
若想对一个 Object 数组进行排序,那么必须解决一个问题。根据什么来判定两个 Object 的顺序呢?不幸的
是,最初的 Java 设计者并不认为这是一个重要的问题,否则就已经在根类 Object 里定义它了。这样造成的
256
…………………………………………………………Page 258……………………………………………………………
一个后果便是:必须从外部进行Object 的排序,而且新的集合库提供了实现这一操作的标准方式(最理想的
是在Object 里定义它)。
针对Object 数组(以及 String,它当然属于Object 的一种),可使用一个 sort(),并令其接纳另一个参
数:实现了 parator 接口(即“比较器”接口,新集合库的一部分)的一个对象,并用它的单个
pare()方法进行比较。这个方法将两个准备比较的对象作为自己的参数使用——若第一个参数小于第二
个,返回一个负整数;若相等,返回零;若第一个参数大于第二个,则返回正整数。基于这一规则,上述例
子的String 部分便可重新写过,令其进行真正按字母顺序的排序:
//: Alphap。java
// Using parator to perform an alphabetic sort
package c08。newcollections;
import java。util。*;
public class Alphap implements parator {
public int pare(Object o1; Object o2) {
// Assume it's used only for Strings。。。
String s1 = ((String)o1)。toLowerCase();
String s2 = ((String)o2)。toLowerCase();
return s1。pareTo(s2);
}
public static void main(String'' args) {
String'' s = Array1。randStrings(4; 10);
Array1。print(s);
Alphap ac = new Alphap();
Arrays。sort(s; ac);
Array1。print(s);
// Must use the parator to search; also:
int loc = Arrays。binarySearch(s; s'3'; ac);
System。out。println(〃Location of 〃 + s'3' +
〃 = 〃 + loc);
}
} ///:~
通过造型为 String,pare()方法会进行“暗示”性的测试,保证自己操作的只能是String 对象——运行
期系统会捕获任何差错。将两个字串都强迫换成小写形式后,String。pareTo()方法会产生预期的结果。
若用自己的 parator 来进行一次 sort(),那么在使用binarySearch()时必须使用那个相同的
parator。
Arrays 类提供了另一个 sort()方法,它会采用单个自变量:一个 Object 数组,但没有parator。这个
sort()方法也必须用同样的方式来比较两个 Object。通过实现parable 接口,它采用了赋予一个类的
“自然比较方法”。这个接口含有单独一个方法——pareTo(),能分别根据它小于、等于或者大于自变量
而返回负数、零或者正数,从而实现对象的比较。下面这个例子简单地阐示了这一点:
//: pClass。java
// A class that implements parable
package c08。newcollections;
import java。util。*;
public class pClass implements parable {
private int i;
public pClass(int ii) { i = ii; }
public int pareTo(Object o) {
// Implicitly tests for correct type:
257
…………………………………………………………Page 259……………………………………………………………
int argi = ((pClass)o)。i;
if(i == argi) return 0;
if(i 《 argi) return …1;
return 1;
}
public static void print(Object'' a) {
for(int i = 0; i 《 a。length; i++)
System。out。print(a'i' + 〃 〃);
System。out。println();
}
public String toString() { return i + 〃〃; }
public static void main(String'' args) {
pClass'' a = new pClass'20';
for(int i = 0; i 《 a。length; i++)
a'i' = new pClass(
(int)(Math。random() *100));
print(a);
Arrays。sort(a);
print(a);
int loc = Arrays。binarySearch(a; a'3');
System。out。println(〃Location of 〃 + a'3' +
〃 = 〃 + loc);
}
} ///:~
当然,我们的 pareTo()方法亦可根据实际情况增大复杂程度。
3。 列表
可用与数组相同的形式排序和搜索一个列表(List )。用于排序和搜索列表的静态方法包含在类
Collections 中,但它们拥有与Arrays 中差不多的签名:sort(List)用于对一个实现了 parable 的对象
列表进行排序;binarySearch(List;Object)用于查找列表中的某个对象;sort(List;parator)利用一个
“比较器”对一个列表进行排序;而binarySearch(List;Object;parator)则用于查找那个列表中的一个
对象(注释⑨)。下面这个例子利用了预先定义好的pClass 和 Alphap 来示范 Collections 中的各种
排序工具:
//: ListSort。java
// Sorting and searching Lists with 'Collections'
package c08。newcollections;
import java。util。*;
public class ListSort {
public static void main(String'' args) {
final int SZ = 20;
// Using 〃natural parison method〃:
List a = new ArrayList();
for(int i = 0; i 《 SZ; i++)
a。add(new pClass(
(int)(Math。random() *100)));
Collection1。print(a);
Collections。sort(a);
Collection1。print(a);
Object find = a。get(SZ/2);
258
…………………………………………………………Page 260……………………………………………………………
int loc = Collections。binarySearch(a; find);
System。out。println(〃Location of 〃 + find +
〃 = 〃 + loc);
// Using a parator:
List b = new ArrayList();
for(int i = 0; i 《 SZ; i++)
b。add(Array1。randString(4));
Collection1。print(b);
Alphap ac = new Alphap();
Collections。sort(b; ac);
Collection1。print(b);
find = b。get(SZ/2);
// Must use the parator to search; also:
loc = Collections。binarySearch(b; find; ac);
System。out。println(〃Location of 〃 + find +
〃 = 〃 + loc);
}
} ///:~
⑨:在本书写作时,已宣布了一个新的Collections。stableSort(),可用它进行合并式排序,但还没有它的
测试版问世。
这些方法的用法与在Arrays 中的用法是完全一致的,只是用一个列表代替了数组。
TreeMap 也必须根据 parable 或者parator 对自己的对象进行排序。
8。7。8 实用工具
Collections 类中含有其他大量有用的实用工具:
enumeration(Collection) Produces an old…style E n u m e r a t i o n for the argument。
m a x ( C o l l e c t i o n ) Produces the maximum or minimum element in the argument using the
m i n ( C o l l e c t i o n ) natural parison method of the objects in the C o l l e c t i o n 。
m a x ( C o l l e c t i o n ; Produces the maximum or minimum element in the Collection using the
C o m p a r a t o r ) C o m p a r a t o r 。
m i n ( C o l l e c t i o n ;
C o m p a r a t o r )
nCopies(int n; Object o) Returns an immutable L i s t of size n whose handles all point to o。
subList(List; int min; int Returns a new L i s t backed by the specified argument List that is a
m a x ) window into that argument with indexes starting at min and stopping
just before max 。
enumeration(Collection) 为自变量产生原始风格的Enumeration (枚举)
max(Collection),min(Collection) 在自变量中用集合内对象的自然比较方法产生最大或最小元素
max(Collection;parator),min(Collection;parator) 在集合内用比较器产生最大或最小元素
nCopies(int n; Object o) 返回长度为 n 的一个不可变列表,它的所有句柄均指向o
subList(List;int min;int max) 返回由指定参数列表后推得到的一个新列表。可将这个列表想象成一个
“窗口”,它自索引为min 的地方开始,正好结束于max 的前面
注意min()和max()都是随同Collection 对象工作的,而非随同 List,所以不必担心Collection 是否需要
排序(就象早先指出的那样,在执行一次 binarySearch()——即二进制搜索——之前,必须对一个 List 或
者一个数组执行 sort())。
259
…………………………………………………………Page 261……………………………………………………………
1。 使 Collection 或 Map 不可修改
通常,创建 Collection 或 Map 的一个“只读”版本显得更有利一些。Collections 类允许我们达到这个目
标,方法是将原始容器传递进入一个方法,并令其传回一个只读版本。这个方法共有四种变化形式,分别用
于Collection (如果不想把集合当作一种更特殊的类型对待)、List、Set 以及Map 。下面这个例子演示了
为它们分别构建只读版本的正确方法:
//: ReadOnly。java
// Using the Collections。unmodifiable methods
package c08。newcollections;
import java。util。*;
public class ReadOnly {
public static void main(String'' args) {
Collection c = new ArrayList();
Collection1。fill(c); // Insert useful data
c = Collections。unmodifiableCollection(c);
Collection1。print(c); // Reading is OK
//! c。add(〃one〃); // Can't change it
List a = new ArrayList();
Collection1。fill(a);
a = Collections。unmodifiableList(a);
ListIterator lit = a。listIterator();
System。out。println(lit。next()); // Reading OK
//! lit。add(〃one〃); // Can't change it
Set s = new HashSet();
Collection1。fill(s);
s = Collections。unmodifiableSet(s);
Collection1。print(s); // Reading OK
//! s。add(〃one〃); // Can't change it
Map m = new HashMap();
Map1。fill(m; Map1。testData1);
m = Collections。unmodifiableMap(m);
Map1。print(m); // Reading OK
//! m。put(〃Ralph〃; 〃Howdy!〃);
}
} ///:~
对于每种情况,在将其正式变为只读以前,都必须用有有效的数据填充容器。一旦载入成功,最佳的做法就
是用“不可修改”调用产生的句柄替换现有的句柄。这样做可有效避免将其变成不可修改后不慎改变其中的
内容。在另一方面,该工具也允许我们在一个类中将能够修改的容器保持为private 状态,并可从一个方法
调用中返回指向那个容器的一个只读句柄。这样一来,虽然我们可在类里修改它,但其他任何人都只能读。
为特定类型调用“不可修改”的方法不会造成编译期间的检查,但一旦发生任何变化,对修改特定容器的方
法的调用便会产生一个 UnsupportedOperationException 违例。
2。 Collection 或Map 的同步
synchronized关键字是“多线程”机制一个非常重要的部分。我们到第 14章才会对这一机制作深入的探
讨。在这儿,大家只需注意到 Collections 类提供了对整个容器进行自动同步的一种途径。它的语法与“不
可修改”的方法是类似的:
260
…………………………………………………………Page 262……………………………………………………………
//: Synchronization。java
// Using the Collections。synchronized methods
package c08。newcollections;
import java。util。*;
public class Synchronization {
public static void main(String'' args) {
Collection c =
Collections。synchronizedCollection(
new ArrayList());
List list = Collections。synchronizedList(
new ArrayList());
Set s = Collectio
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!