友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!阅读过程发现任何错误请告诉我们,谢谢!! 报告错误
一世书城 返回本书目录 我的书架 我的书签 TXT全本下载 进入书吧 加入书签

Java编程思想第4版[中文版](PDF格式)-第86章

按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!




      〃”): 〃 + 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 的“特点”是它们都属于“传统”类,所以不会干扰原有的代码。但在 

另一方面,应尽量避免为新的(Java 1。2 )代码使用它们。  

其他集合间的差异通常都可归纳为它们具体是由什么“后推”的。换言之,取决于物理意义上用于实施目标 

接口的数据结构是什么。例如,ArrayList,LinkedList 以及Vector (大致等价于ArrayList)都实现了 

List 接口,所以无论选用哪一个,我们的程序都会得到类似的结果。然而,ArrayList (以及Vector)是由 

一个数组后推得到的;而LinkedList 是根据常规的双重链接列表方式实现的,因为每个单独的对象都包含了 

数据以及指向列表内前后元素的句柄。正是由于这个原因,假如想在一个列表中部进行大量插入和删除操 

作,那么LinkedList 无疑是最恰当的选择(LinkedList 还有一些额外的功能,建立于 

AbstractSequentialList 中)。若非如此,就情愿选择ArrayList ,它的速度可能要快一些。  

作为另一个例子,Set 既可作为一个ArraySet 实现,亦可作为HashSet 实现。ArraySet 是由一个ArrayList 

后推得到的,设计成只支持少量元素,特别适合要求创建和删除大量 Set 对象的场合使用。然而,一旦需要 

在自己的Set 中容纳大量元素,ArraySet 的性能就会大打折扣。写一个需要 Set 的程序时,应默认选择 

HashSet。而且只有在某些特殊情况下(对性能的提升有迫切的需求),才应切换到ArraySet 。  

  

1。 决定使用何种List  

为体会各种 List 实施方案间的差异,最简便的方法就是进行一次性能测验。下述代码的作用是建立一个内部 

基础类,将其作为一个测试床使用。然后为每次测验都创建一个匿名内部类。每个这样的内部类都由一个 

test()方法调用。利用这种方法,可以方便添加和删除测试项目。  

  

//: ListPerformance。java  

// Demonstrates performance differences in Lists  

package c08。newcollections;  

import java。util。*;  

  

public class ListPerformance {  

  private static final int REPS = 100;  

  private abstract static class Tester {  

    String name;  

    int size; // Test quantity  

    Tester(String name; int size) {   

      this。name = name;  

      this。size = size;  

    }  

    abstract void test(List a);  

  }  

  private static Tester'' tests = {  

    new Tester(〃get〃; 300) {   

      void test(List a) {  

        for(int i = 0; i 《 REPS; i++) {  

          for(int j = 0; j 《 a。size(); j++)  

            a。get(j);  

        }  

      }  

    };  



                                                                                     247 


…………………………………………………………Page 249……………………………………………………………

    new Tester(〃iteration〃; 300) {   

      void test(List a) {  

        for(int i = 0; i 《 REPS; i++) {  

          Iterator it = a。iterator();  

          while(it。hasNext())  

            it。next();  

        }  

      }  

    };  

    new Tester(〃insert〃; 1000) {   

      void test(List a) {  

        int half = a。size()/2;  

        String s = 〃test〃;  

        ListIterator it = a。listIterator(half);  

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

          it。add(s);  

      }  

    };  

    new Tester(〃remove〃; 5000) {   

      void test(List a) {  

        ListIterator it = a。listIterator(3);  

        while(it。hasNext()) {  

          it。next();  

          it。remove();  

        }  

      }  

    };  

  };  

  public static void test(List a) {  

    // A trick to print out the class name:  

    System。out。println(〃Testing 〃 +   

      a。getClass()。getName());  

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

      Collection1。fill(a; tests'i'。size);  

      System。out。print(tests'i'。name);  

      long t1 = System。currentTimeMillis();  

      tests'i'。test(a);  

      long t2 = System。currentTimeMillis();  

      System。out。println(〃: 〃 + (t2 t1));  

    }  

  }  

  public static void main(String'' args) {  

    test(new ArrayList());  

    test(new LinkedList());  

  }  

} ///:~  

  

内部类Tester 是一个抽象类,用于为特定的测试提供一个基础类。它包含了一个要在测试开始时打印的字 

串、一个用于计算测试次数或元素数量的size 参数、用于初始化字段的一个构建器以及一个抽象方法 

test()。test()做的是最实际的测试工作。各种类型的测试都集中到一个地方:tests 数组。我们用继承于 

Tester 的不同匿名内部类来初始化该数组。为添加或删除一个测试项目,只需在数组里简单地添加或移去一 

个内部类定义即可,其他所有工作都是自动进行的。  



                                                                                          248 


…………………………………………………………Page 250……………………………………………………………

首先用元素填充传递给 test()的List,然后对tests 数组中的测试计时。由于测试用机器的不同,结果当然 

也会有所区别。这个程序的宗旨是揭示出不同集合类型的相对性能比较。下面是某一次运行得到的结果:  

  

  



Type       Get  Iteration Insert Remove  



ArrayList 110  490        3790   8730  



LinkedList 1980 220       110    110  



  

可以看出,在ArrayList 中进行随机访问(即get())以及循环反复是最划得来的;但对于LinkedList 却是 

一个不小的开销。但另一方面,在列表中部进行插入和删除操作对于 LinkedList 来说却比ArrayList 划算得 

多。我们最好的做法也许是先选择一个ArrayList 作为自己的默认起点。以后若发现由于大量的插入和删除 

造成了性能的降低,再考虑换成LinkedList 不迟。  

  

2。 决定使用何种 Set  

可在ArraySet 以及HashSet 间作出选择,具体取决于Set 的大小(如果需要从一个Set 中获得一个顺序列 

表,请用TreeSet;注释⑧)。下面这个测试程序将有助于大家作出这方面的抉择:  

  

//: SetPerformance。java  

package c08。newcollections;  

import java。util。*;  

  

public class SetPerformance {  

  private static final int REPS = 200;  

  private abstract static class Tester {  

    String name;  

    Tester(String name) { this。name = name; }  

    abstract void test(Set s; int size);  

  }  

  private static Tester'' tests = {  

    new Tester(〃add〃) {   

      void test(Set s; int size) {  

        for (int i = 0; i 《 REPS; i++) {  

          s。clear();  

          Collection1。fill(s; size);  

        }  

      }  

    };  

    new Tester(〃contains〃) {   

      void test(Set s; int size) {  

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

          for(i
返回目录 上一页 下一页 回到顶部 0 0
未阅读完?加入书签已便下次继续阅读!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!