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

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

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


完全就是一个Collection,只是具有不同的行为(这是实例和多形性最理想的应用:用于表达不同的行 

为)。在这里,一个Set 只允许每个对象存在一个实例(正如大家以后会看到的那样,一个对象的“值”的 

构成是相当复杂的)。  

  



S e t        Each element that you add to the Set  must be unique; otherwise the Set  doesn’t  

(interface) add the duplicate element。 Objects added to a Set  must define e q u a l s (   )  to  

             establish object uniqueness。 Set  has exactly the same interface as Collection。 The  

             Set  interface does not guarantee it will maintain its elements in any particular  

             order。  



H a s h S e t *   For Set s where fast lookup time is important。 Objects must also define  

             h a s h C o d e (  ) 。  



T r e e S e t   An ordered Set  backed by a red…black tree。 This way; you can extract an ordered  

             sequence from a Set 。  



  

  

Set (接口) 添加到 Set 的每个元素都必须是独一无二的;否则Set 就不会添加重复的元素。添加到 Set 里 

的对象必须定义equals(),从而建立对象的唯一性。Set 拥有与 Collection 完全相同的接口。一个 Set不能 

保证自己可按任何特定的顺序维持自己的元素  

HashSet* 用于除非常小的以外的所有Set。对象也必须定义hashCode()  

ArraySet  由一个数组后推得到的Set。面向非常小的Set 设计,特别是那些需要频繁创建和删除的。对于小 

Set,与HashSet 相比,ArraySet 创建和反复所需付出的代价都要小得多。但随着 Set 的增大,它的性能也 

会大打折扣。不需要HashCode()  



                                                                                              242 


…………………………………………………………Page 244……………………………………………………………

TreeSet  由一个“红黑树”后推得到的顺序Set (注释⑦)。这样一来,我们就可以从一个Set 里提到一个 

顺序集合  

  

⑦:直至本书写作的时候,TreeSet 仍然只是宣布,尚未正式实现。所以这里没有提供使用TreeSet 的例 

子。  

  

下面这个例子并没有列出用一个Set 能够做的全部事情,因为接口与Collection 是相同的,前例已经练习过 

了。相反,我们要例示的重点在于使一个Set 独一无二的行为:  

  

//: Set1。java  

// Things you can do with Sets  

package c08。newcollections;  

import java。util。*;  

  

public class Set1 {  

  public static void testVisual(Set a) {  

    Collection1。fill(a);  

    Collection1。fill(a);  

    Collection1。fill(a);  

    Collection1。print(a); // No duplicates!  

    // Add another set to this one:  

    a。addAll(a);  

    a。add(〃one〃);   

    a。add(〃one〃);   

    a。add(〃one〃);  

    Collection1。print(a);  

    // Look something up:  

    System。out。println(〃a。contains(”one”): 〃 +  

      a。contains(〃one〃));  

  }  

  public static void main(String'' args) {  

    testVisual(new HashSet());  

    testVisual(new TreeSet());  

  }  

} ///:~  

  

重复的值被添加到 Set,但在打印的时候,我们会发现Set 只接受每个值的一个实例。  

运行这个程序时,会注意到由 HashSet 维持的顺序与ArraySet 是不同的。这是由于它们采用了不同的方法来 

保存元素,以便它们以后的定位。ArraySet 保持着它们的顺序状态,而HashSet 使用一个散列函数,这是特 

别为快速检索设计的)。创建自己的类型时,一定要注意 Set 需要通过一种方式来维持一种存储顺序,就象 

本章早些时候展示的“groundhog”(土拔鼠)例子那样。下面是一个例子:  

  

//: Set2。java  

// Putting your own type in a Set  

package c08。newcollections;  

import java。util。*;  

  

class MyType implements parable {  

  private int i;  

  public MyType(int n) { i = n; }  

  public boolean equals(Object o) {  

    return   



                                                                                          243 


…………………………………………………………Page 245……………………………………………………………

      (o instanceof MyType)   

      && (i == ((MyType)o)。i);  

  }  

  public int hashCode() { return i; }  

  public String toString() { return i + 〃 〃; }  

  public int pareTo(Object o) {  

    int i2 = ((MyType) o)。i;  

    return (i2 《 i ? …1 : (i2 == i ? 0 : 1));  

  }  

}  

  

public class Set2 {  

  public static Set fill(Set a; int size) {  

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

      a。add(new MyType(i));  

    return a;  

  }  

  public static Set fill(Set a) {  

    return fill(a; 10);  

  }  

  public static void test(Set a) {  

    fill(a);  

    fill(a); // Try to add duplicates  

    fill(a);  

    a。addAll(fill(new TreeSet()));  

    System。out。println(a);  

  }  

  public static void main(String'' args) {  

    test(new HashSet());  

    test(new TreeSet());  

  }  

} ///:~  

  

对 equals()及hashCode()的定义遵照“groundhog”例子已经给出的形式。在两种情况下都必须定义一个 

equals()。但只有要把类置入一个HashSet 的前提下,才有必要使用hashCode()——这种情况是完全有可能 

的,因为通常应先选择作为一个Set 实现。  



8。7。4  使用 Maps   



  



M a p         Maintains key…value associations (pairs); so you can look up a value using a key。  

(interface)  



H a s h M a p *   Implementation based on a hash table。 (Use this instead of Hashtable。) Provides  

              constant…time performance for inserting and locating pairs。 Performance can be  

              adjusted via constructors that allow you to set the capacity and load factor of  

              the hash table。  



T r e e M a p   Implementation based on a red…black tree。 When you view the keys or the pairs;  

              they will be in sorted order (determined by parable or parator; discussed  

              later)。 The point of a T r e e M a p  is that you get the results in sorted order。  

              T r e e M a p   is the only M a p  with the s u b M a p (   )  method; which allows you to return a  

              portion of the tree。  



                                                                                                       244 


…………………………………………………………Page 246……………………………………………………………

  

  

Map (接口) 维持“键-值”对应关系(对),以便通过一个键查找相应的值  

HashMap* 基于一个散列表实现(用它代替Hashtable)。针对“键-值”对的插入和检索,这种形式具有 

最稳定的性能。可通过构建器对这一性能进行调整,以便设置散列表的“能力”和“装载因子”  

ArrayMap 由一个ArrayList 后推得到的Map 。对反复的顺序提供了精确的控制。面向非常小的Map 设计,特 

别是那些需要经常创建和删除的。对于非常小的Map,创建和反复所付出的代价要比HashMap 低得多。但在 

Map 变大以后,性能也会相应地大幅度降低  

TreeMap 在一个“红-黑”树的基础上实现。查看键或者“键-值”对时,它们会按固定的顺序排列(取决 

于parable 或parator,稍后即会讲到)。TreeMap 最大的好处就是我们得到的是已排好序的结果。 

TreeMap 是含有 subMap()方法的唯一一种Map,利用它可以返回树的一部分  

  

下例包含了两套测试数据以及一个 fill()方法,利用该方法可以用任何两维数组(由Object 构成)填充任 

何Map 。这些工具也会在其他Map 例子中用到。  

  

//: Map1。java  

// Things you can do with Maps  

package c08。newcollections;  

import java。util。*;  

  

public class Map1 {  

  public final static String'''' testData1 = {  

    { 〃Happy〃; 〃Cheerful disposition〃 };  

    { 〃Sleepy〃; 〃Prefers dark; quiet places〃 };  

    { 〃Grumpy〃; 〃Needs to work on attitude〃 };  

    { 〃Doc〃; 〃Fantasizes about advanced degree〃};  

    { 〃Dopey〃; 〃'A' for effort〃 };  

    { 〃Sneezy〃; 〃Struggles with allergies〃 };  

    { 〃Bashful〃; 〃Needs self…esteem workshop〃};  

  };  

  public final static String'''' testData2 = {  

    { 〃Belligerent〃; 〃Disruptive influence〃 };  

    { 〃Lazy〃; 〃Motivational problems〃 };  

    { 〃atose〃; 〃Excellent behavior〃 }  

  };  

  public static Map fill(Map m; Object'''' o) {  

    for(int i = 0; i 《 o。length; i++)  

      m。put(o'i''0'; o'i''1');  

    return m;  

  }  

  // Producing a Set of the keys:  

  public static void printKeys(Map m) {  

    System。out。print(〃Size = 〃 + m。size() +〃; 〃);  

    System。out。print(〃Keys: 〃);  

    Collection1。print(m。keySet());  

  }  

  // Producing a Collection of the values:  

  public static void printValues(Map m) {  

    System。out。print(〃Values: 〃);  

    Collection1。print(m。values());  

  }  

  // Iterating through Map。Entry objects (pairs):  



                                                                                          245 


…………………………………………………………Page 247……………………………………………………………

  public static void print(Map m) {  

    Collection entries = m。entries();  

    Iterator it = entries。iterator();  

    while(it。hasNext()) {  

      Map。Entry e = (Map。Entry)it。next();  

      System。out。println(〃Key = 〃 + e。getKey() +  

        〃; Value = 〃 + e。getValue());  

    }  

  }  

  public static void test(Map m) {  

    fill(m; testData1);  

    // Map has 'Set' behavior for keys:  

    fill(m; testData1);  

    printKeys(m);  

    printValues(m);  

    print(m);  

    String key = testData1'4''0';  

    String value = testData1'4''1';  

    System。out。println(〃m。containsKey(”〃 + key +  

      〃”): 〃 + m。containsKey(key));  

    System。out。println(〃m。get(”〃 + key + 〃”): 〃  

      + m。get(key));  

    System。out。println(〃m。containsValue( ”〃   

      + value + 〃”): 〃 +   

      m。containsValue(value));   

    Map m2 = fill(new TreeMap(); testData2);  

    m。putAll(m2);  

    printKeys(m);  

    m。remove(testData2'0''0');  

    printKeys(m);  

    m。clear();  

    System。out。println(〃m。isEmpty(): 〃   

      + m。isEmpty());  

    fill(m; testData1);  

    // Operations on the Set change the Map:  

    m。keySet()。removeAll(m。keySet());  

    System。out。println(〃m。isEmpty(): 〃   

      + m。isEmpty());  

  }  

  public static void main(String args'') {  

    System。out。println(〃Testing HashMap〃);  

    test(new HashMap());  

    System。out。println(〃Testing TreeMap〃);  

    test(new TreeMap());  

  }  

} ///:~  

  

printKeys(),printValues() 以及print()方法并不只是有用的工具,它们也清楚地揭示了一个Map 的 

Collection “景象”的产生过程。keySet()方法会产生一个Set,它由Map 中的键后推得来。在这儿,它只 

被当作一个 Collection 对待。values()也得到了类似的对待,它的作用是产生一个 List,其中包含了Map 

中的所有值(注意键必须是独一无二的,而值可以有重复)。由于这些Collection 是由Map 后推得到的,所 

以一个Collection 中的任何改变都会在相应的Map 中反映出来。  



                                                                                          246 


…………………………………………………………Page 248……………………………………………………………

print()方法的作用是收集由entries 产生的 Iterator (反复器),并用它同时打印出每个“键-值”对的 

键和值。程序剩余的部分提供了每种Map 操作的简单示例,并对每种类型的 Map 进行了测试。  

当创建自己的类,将其作为Map 中的一个键使用时,必须注意到和以前的 Set 相同的问题。  



8。7。5  决定实施方案  



从早些时候的那幅示意图可以看出,实际上只有三个集合组件:Map,List 和 Set。而且每个接口只有两种或 

三种实施方案。若需使用由一个特定的接口提供的功能,如何才能决定到底采取哪一种方案呢?  

为理解这个问题,必须认识到每种不同的实施方案都有自己的特点、优点和缺点。比如在那张示意图中,可 

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