友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
富士康小说网 返回本书目录 加入书签 我的书架 我的书签 TXT全本下载 『收藏到我的浏览器』

Java编程思想第4版[中文版](PDF格式)-第44部分

快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!



能保证一切都正确无误吗?(也就是说,“代码测试时也许不能保证”,以及“该程序的用户有可能做一些 

未经我们测试的事情”)。尽管存在其他选择和争论,使用继承都要容易得多,只是在造型时让人深感不 

便。同样地,一旦为Java 加入参数化类型,就有望解决这个问题。  

大家在这个类中可以看到有一个名为“sorted”的标志。每次调用addElement()时,都可对 Vector 进行排 

序,而且将其连续保持在一个排好序的状态。但在开始读取之前,人们总是向一个Vector 添加大量元素。所 

以与其在每个addElement()后排序,不如一直等到有人想读取Vector,再对其进行排序。后者的效率要高得 

多。这种除非绝对必要,否则就不采取行动的方法叫作“懒惰求值”(还有一种类似的技术叫作“懒惰初始 

化”——除非真的需要一个字段值,否则不进行初始化)。  



8。6 通用集合库  



通过本章的学习,大家已知道标准 Java 库提供了一些特别有用的集合,但距完整意义的集合尚远。除此之 

外,象排序这样的算法根本没有提供支持。C++出色的一个地方就是它的库,特别是“标准模板库”(STL) 

提供了一套相当完整的集合,以及许多象排序和检索这样的算法,可以非常方便地对那些集合进行操作。有 

感这一现状,并以这个模型为基础,ObjectSpace 公司设计了 Java 版本的“通用集合库”(从前叫作“Java 

通用库”,即JGL;但JGL 这个缩写形式侵犯了Sun 公司的版权——尽管本书仍然沿用这个简称)。这个库 

尽可能遵照 STL 的设计(照顾到两种语言间的差异)。JGL 实现了许多功能,可满足对一个集合库的大多数 



                                                                                     232 


…………………………………………………………Page 234……………………………………………………………

常规需求,它与C++的模板机制非常相似。JGL 包括相互链接起来的列表、设置、队列、映射、堆栈、序列以 

及反复器,它们的功能比Enumeration (枚举)强多了。同时提供了一套完整的算法,如检索和排序等。在 

某些方面,ObjectSpace 的设计也显得比Sun 的库设计方案“智能”一些。举个例子来说,JGL 集合中的方法 

不会进入final 状态,所以很容易继承和改写那些方法。  

JGL 已包括到一些厂商发行的Java 套件中,而且 ObjectSpace 公司自己也允许所有用户免费使用 JGL,包括 

商业性的使用。详细情况和软件下载可访问http://ObjectSpace。。与JGL 配套提供的联机文档做得 

非常好,可作为自己的一个绝佳起点使用。  



8。7 新集合  



对我来说,集合类属于最强大的一种工具,特别适合在原创编程中使用。大家可能已感觉到我对 Java 1。1 提 

供的集合多少有点儿失望。因此,看到Java 1。2 对集合重新引起了正确的注意后,确实令人非常愉快。这个 

版本的集合也得到了完全的重新设计(由 Sun 公司的Joshua B loch)。我认为新设计的集合是Java 1。2 中 

两项最主要的特性之一(另一项是 Swing 库,将在第 13 章叙述),因为它们极大方便了我们的编程,也使 

Java 变成一种更成熟的编程系统。  

有些设计使得元素间的结合变得更紧密,也更容易让人理解。例如,许多名字都变得更短、更明确了,而且 

更易使用;类型同样如此。有些名字进行了修改,更接近于通俗:我感觉特别好的一个是用“反复器” 

 (Inerator )代替了“枚举”(Enumeration)。  

此次重新设计也加强了集合库的功能。现在新增的行为包括链接列表、队列以及撤消组队(即“双终点队 

列”)。  

集合库的设计是相当困难的(会遇到大量库设计问题)。在C++中,STL 用多个不同的类来覆盖基础。这种做 

法比起 STL 以前是个很大的进步,那时根本没做这方面的考虑。但仍然没有很好地转换到Java 里面。结果就 

是一大堆特别容易混淆的类。在另一个极端,我曾发现一个集合库由单个类构成:colleciton,它同时作为 

Vector 和 Hashtable 使用。新集合库的设计者则希望达到一种新的平衡:实现人们希望从一个成熟集合库上 

获得的完整功能,同时又要比 STL 和其他类似的集合库更易学习和使用。这样得到的结果在某些场合显得有 

些古怪。但和早期 Java 库的一些决策不同,这些古怪之处并非偶然出现的,而是以复杂性作为代价,在进行 

仔细权衡之后得到的结果。这样做也许会延长人们掌握一些库概念的时间,但很快就会发现自己很乐于使用 

那些新工具,而且变得越来越离不了它。  

新的集合库考虑到了“容纳自己对象”的问题,并将其分割成两个明确的概念:  

(1) 集合(Collection):一组单独的元素,通常应用了某种规则。在这里,一个List (列表)必须按特定 

的顺序容纳元素,而一个Set (集)不可包含任何重复的元素。相反,“包”(Bag)的概念未在新的集合库 

中实现,因为“列表”已提供了类似的功能。  

(2) 映射(Map):一系列“键-值”对(这已在散列表身上得到了充分的体现)。从表面看,这似乎应该成 

为一个“键-值”对的“集合”,但假若试图按那种方式实现它,就会发现实现过程相当笨拙。这进一步证 

明了应该分离成单独的概念。另一方面,可以方便地查看Map 的某个部分。只需创建一个集合,然后用它表 

示那一部分即可。这样一来,Map 就可以返回自己键的一个Set、一个包含自己值的List 或者包含自己“键 

-值”对的一个List 。和数组相似,Map 可方便扩充到多个“维”,毋需涉及任何新概念。只需简单地在一 

个Map 里包含其他Map (后者又可以包含更多的Map,以此类推)。  

  

Collection 和 Map 可通过多种形式实现,具体由编程要求决定。下面列出的是一个帮助大家理解的新集合示 

意图:  

  



                                                                 233 


…………………………………………………………Page 235……………………………………………………………

                                                            

  

这张图刚开始的时候可能让人有点儿摸不着头脑,但在通读了本章以后,相信大家会真正理解它实际只有三 

个集合组件:Map,List 和 Set。而且每个组件实际只有两、三种实现方式(注释⑥),而且通常都只有一种 

特别好的方式。只要看出了这一点,集合就不会再令人生畏。  

  

⑥:写作本章时,Java 1。2 尚处于β测试阶段,所以这张示意图没有包括以后会加入的TreeSet。  

  

虚线框代表“接口”,点线框代表“抽象”类,而实线框代表普通(实际)类。点线箭头表示一个特定的类 

准备实现一个接口(在抽象类的情况下,则是“部分”实现一个接口)。双线箭头表示一个类可生成箭头指 

向的那个类的对象。例如,任何集合都可以生成一个反复器(Iterator),而一个列表可以生成一个 

ListIterator (以及原始的反复器,因为列表是从集合继承的)。  

致力于容纳对象的接口是Collection,List,Set 和Map。在传统情况下,我们需要写大量代码才能同这些 

接口打交道。而且为了指定自己想使用的准确类型,必须在创建之初进行设置。所以可能创建下面这样的一 

个List :  

List x = new LinkedList();  

当然,也可以决定将x 作为一个LinkedList 使用(而不是一个普通的List ),并用x 负载准确的类型信 

息。使用接口的好处就是一旦决定改变自己的实施细节,要做的全部事情就是在创建的时候改变它,就象下 

面这样:  

List x = new ArrayList();  

其余代码可以保持原封不动。  

在类的分级结构中,可看到大量以“Abstract ”(抽象)开头的类,这刚开始可能会使人感觉迷惑。它们实 

际上是一些工具,用于“部分”实现一个特定的接口。举个例子来说,假如想生成自己的Set,就不是从 Set 

接口开始,然后自行实现所有方法。相反,我们可以从AbstractSet 继承,只需极少的工作即可得到自己的 

新类。尽管如此,新集合库仍然包含了足够的功能,可满足我们的几乎所有需求。所以考虑到我们的目的, 

可忽略所有以“Abstract ”开头的类。  

因此,在观看这张示意图时,真正需要关心的只有位于最顶部的“接口”以及普通(实际)类——均用实线 

方框包围。通常需要生成实际类的一个对象,将其上溯造型为对应的接口。以后即可在代码的任何地方使用 



                                                                        234 


…………………………………………………………Page 236……………………………………………………………

那个接口。下面是一个简单的例子,它用 String 对象填充一个集合,然后打印出集合内的每一个元素:  

  

//: SimpleCollection。java  

// A simple example using the new Collections  

package c08。newcollections;  

import java。util。*;  

  

public class SimpleCollection {  

  public static void main(String'' args) {  

    Collection c = new ArrayList();  

    for(int i = 0; i 《 10; i++)  

      c。add(Integer。toString(i));  

    Iterator it = c。iterator();  

    while(it。hasNext())  

      System。out。println(it。next());  

  }  

} ///:~  

  

新集合库的所有代码示例都置于子目录newcollections 下,这样便可提醒自己这些工作只对于Java 1。2 有 

效。这样一来,我们必须用下述代码来调用程序:  

java c08。newcollections。SimpleCollection  

采用的语法与其他程序是差不多的。  

大家可以看到新集合属于java。util 库的一部分,所以在使用时不需要再添加任何额外的 import语句。  

main()的第一行创建了一个ArrayList 对象,然后将其上溯造型成为一个集合。由于这个例子只使用了 

Collection 方法,所以从 Collection 继承的一个类的任何对象都可以正常工作。但ArrayList 是一个典型 

的Collection,它代替了 Vector 的位置。  

显然,add()方法的作用是将一个新元素置入集合里。然而,用户文档谨慎地指出 add() “保证这个集合包含 

了指定的元素”。这一点是为Set 作铺垫的,后者只有在元素不存在的前提下才会真的加入那个元素。对于 

ArrayList 以及其他任何形式的List,add()肯定意味着“直接加入”。  

利用 iterator()方法,所有集合都能生成一个“反复器”(Iterator)。反复器其实就象一个“枚举” 

 (Enumeration),是后者的一个替代物,只是:  

(1) 它采用了一个历史上默认、而且早在OOP 中得到广泛采纳的名字(反复器)。  

(2) 采用了比Enumeration 更短的名字:hasNext()代替了 hasMoreElement(),而next()代替了 

nextElement() 。  

(3) 添加了一个名为remove() 的新方法,可删除由Iterator 生成的上一个元素。所以每次调用 next()的时 

候,只需调用remove()一次。  

在SimpleCollection。java 中,大家可看到创建了一个反复器,并用它在集合里遍历,打印出每个元素。  



8。7。1  使用 Collections  



下面这张表格总结了用一个集合能做的所有事情(亦可对 Set 和List 做同样的事情,尽管 List 还提供了一 

些额外的功能)。Map 不是从Collection 继承的,所以要单独对待。  

  

  



B o o l e a n  a d d ( O b j e c t )  *Ensures that the Collection contains the argument。 Returns false if  

                          it doesn ’t add the argument。  



B o o l e a n            *Adds all the elements in the argument。 Returns true if any elements  

a d d A l l ( C o l l e c t i o n )  were added。  



v o i d   c l e a r (  )   *Removes all the elements in the Collection。   



Boolean contains(Object) True if the Collection contains the argument。   



B o o l e a n            True if the Collection contains all the elements in the argument。  



                                                                                          235 


…………………………………………………………Page 237……………………………………………………………

containsAll(Collection)  



B o o l e a n   i s E m p t y (   )   True if the Collection has no elements。   



Iterator iterator( )  Returns an Iterator that you can use to move through the elements in  

                           the Collection。   



Boolean remove(Object) *If the argument is in the Collection; one instance of that element  

                           is removed。 Returns true if a removal occurred。  



B o o l e a n              *Removes all the elements that are contained in the argument。  

removeAll(Collection) Returns true if any removals occurred。  



B o o l e a n              *Retains only elements that are contained in the argument (an  

retainAll(Collection)  “intersection” from set theory)。 Returns true if any changes  

                           occurred。  



i n t   s i z e (  )       Returns the number of elements in the Collection。   



O b j e c t ' '  t o A r r a y (  )  Returns an array containing all the elements in the Collection。  



O b j e c t ' '            Returns an array containing all the elements in the Collection;  

t o A r r a y ( O b j e c t ' '  a )  whose type is that of the array a  rather than plain Object (you must  

                           cast the array to the right type)。  



                           *This is an  “optional ” method; which means it might not be  

                           implemented by a particular Collection。 If not; that method throws  

                           an U n s u p p o r t e d O p e r a t i o n E x c e p t i o n 。 Exceptions will be covered in  

                           Chapter 9。  



  

boolean add(Object) *保证集合内包含了自变量。如果它没有添加自变量,就返回false (假)  

boolean addAll(Collection)  *添加自变量内的所有元素。如果没有添加元素,则返回true (真)  

void clear()  *删除集合内的所有元素  

boolean contains(Object) 若集合包含自变量,就返回“真”  

boolean containsAll(Collection) 若集合包含了自变量内的所有元素,就返回“真”  

boolean isEmpty() 若集合内没有元素,就返回“真”  

Iterator iterator() 返回一个反复器,以用它遍历集合的各元素  

boolean remove(Object)  *如自变量在集合里,就删除那个元素的一个实例。如果已进行了删除,就返回 

 “真”  

boolean removeAll(Collection) *删除自变量里的所有元素。如果已进行了任何删除,就返回“真”  

boolean retainAll(Collection) *只保留包含在一个自变量里的元素(一个理论的“交集”)。如果已进 

行了任何改变,就返回“真”  

int size() 返回集合内的元素数量  

Object'' toArray() 返回包含了集合内所有元素的一个数组  

  

*这是一个“可选的”方法,有的集合可能并未实现它。若确实如此,该方法就会遇到一个 

UnsupportedOperatiionException,即一个“操作不支持”违例,详见第9 章。  

  

下面这个例子向大家演示了所有方法。同样地,它们只对从集合继承的东西有效,一个ArrayList 作为一种 

 “不常用的分母”使用:  

  

//: Collection1。java  

// Things you can do with all Collections  

package c08。newcollections;  

import java。util。*;  

  

public class Collection1 {  

  // Fill with 'size' elements; start  



                                                                                               236 


…………………………………………………………Page 238……………………………………………………………

  // counting at 'start':  

  public static Collection   

  fill(Collection c; int start; int size) {  

    for(int i = start; i 《 start + size; i++)  

      c。add(Integer。toString(i));  

    return c;  

  }  

  // Default to a 〃start〃 of 0:  

  public static Collection   

  fill(Collection c; int size) {  

    return fill(c; 0; size);  

  }  

  // Default to 10 elements:  

  public static Collection fill(Collection c) {  

    return fill(c; 0; 10);  

  }  

  // Create & upcast to Collection:  

  public static Collection newCollection() {  

    return fill(new ArrayList());  

    // ArrayList is used for simplicity; but it's  

    // only seen as a generic Collection   

    // everywhere else in the program。  

  }  

  // Fill a Collection with a range of values:  

  public static Collection   

  newCollection(int start; int size) {  

    return fill(new ArrayList(); start; size);  

  }  

  // Moving through a List with an iterator:  

  public static void print(Collection c) {  

    for(Iterator x = c。iterator(); x。hasNext();)  

      System。out。print(x。next() + 〃 〃);  

    System。out。println();  

  }      

  public static void main(String'' args) {  

    Collection c = newCollection();  

    c。add (〃ten〃);  

    c。add(〃eleven〃);  

    print(c);  

    // Make an array from the List:  

    Object'' array = c。toArray();   

    // Make a String array from the List:  

    String'' str =   

      (String'')c。toArray(new String'1');  

    // Find max and min elements; this means  

    // different things depending on the way  

    // the parable interface is implemented:  

    System。out。println(〃Collections。max(c) = 〃 +  

      Collections。max(c));  

    System。out。println(〃Collections。min(c) = 〃 +  

      Collections。min(c));  

    // Add a Collection to another Collection  



                                                                                           237 


…………………………………………………………Page 239……………………………………………………………

    c。addAll(newCollection());  

    print(c);  

    c。remove(〃3〃); // Removes the first one  

    print(c);  

    c。remove(〃3〃); // Removes the second one  

    print(c);
返回目录 上一页 下一页 回到顶部 10 9
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!