Java的集合框架

您可能已经非常熟悉新的 Java™ 5 语言的泛型支持、并发工具库以及它们对集合框架的影响,但是这些并不是 Tiger 中集合框架的惟一变化。这个月,John Zukowski 将介绍另外几项增强,其中包括新的集合类型,以及现有类和接口的附加特性。请参与本文的 讨论论坛。(可以单击文章顶部的 讨论 来访问该论坛。)

JDK 5.0 中最吸引人的地方在于集合框架的一些最突出的特性上,例如:支持泛型的语言级别上的新变化,以及可以在 java.util.concurrent 包中找到的并发集合工具包。实际上,以前在 developerWorks 上的驯服 Tiger: 并发集合介绍 JDK 5.0 中的泛型这两篇教程中介绍了上述特性。但是其他增强还没有得到足够的重视。在本文中,我将研究其他三个变化:更新过的 Arrays Collections 类、新的 Queue 接口以及它的 PriorityQueue 实现。

数组(Array

Arrays 类提供了一系列处理数组的静态工具方法,这些索引的数据结构的大小是固定的。在 5.0 版本之前,Arrays 类拥有针对原始数据库类型和通用 Object 类型的每种不同数组类型的 binarySearch()equals()fill() sort() 方法。用于将 Object 数组转换成 List 的附加 asList() 方法仍然有用。Tiger 为所有数组添加了 hashCode() toString() 方法,还添加了特定于 Object 数组的 deepEquals()deepHashCode() deepToString() 方法。总计有 21 个新方法可用:

  • public static boolean deepEquals(Object[] a1, Object[] a2)
  • public static int deepHashCode(Object[] a)
  • public static String deepToString(Object[] a)
  • public static int hashCode(boolean[] a)
  • public static int hashCode(byte[] a)
  • public static int hashCode(char[] a)
  • public static int hashCode(double[] a)
  • public static int hashCode(float[] a)
  • public static int hashCode(int[] a)
  • public static int hashCode(long[] a)
  • public static int hashCode(Object[] a)
  • public static int hashCode(short[] a)
  • public static String toString(boolean[] a)
  • public static String toString(byte[] a)
  • public static String toString(char[] a)
  • public static String toString(double[] a)
  • public static String toString(float[] a)
  • public static String toString(int[] a)
  • public static String toString(long[] a)
  • public static String toString(Object[] a)
  • public static String toString(short[] a)

自从集合框架初次出现在 J2SE 1.2 中以来,人们第一次对实用工具类进行了更改。我无法确定为什么 Sun 要等这么久才进行更改,但是对于可用的帮助器方法系列来说,这些更改是受欢迎的添加。

新添加的第一个方法是 hashCode()。对于任意数组类型,都可以调用 Arrays.hashCode(arrayVar) 方法来获得格式良好的哈希码。这个哈希码可以用作 HashMap 或者其他相关目的的键。如果您不知道如何生成良好的哈希码,那么最好使用 Arrays 类,它能产生更少冲突。Arrays 类生成等价于拥有相同元素的 List 的代码。

在创建自己的类时,既需要提供 equals() 方法,又需要提供 hashCode() 方法。在 Arrays 的新方法 hashCode() 的帮助下,可以为任何本地数组类型生成哈希码,而不用在每次需要它的时候折腾您自己。

所有数组类型都可用的另一个方法是 toString()。对于任何数组类型,都可以调用 Arrays.toString(arrayVar) 获得逗号分隔的元素列表,列表用方括号包围,如清单 1 的程序所示:


清单 1. Arrays.toString 生成字符串

 

import java.util.Arrays;

 

public class ArgsToString {

  public static void main(String args[]) {

    System.out.println(Arrays.toString(args));

  }

}

 

清单 2 显示了结果:


清单 2. 清单 1 的结果

>java ArgsToString One Two Three

  [One, Two, Three]

 

新的 deepEquals()deepHashCode() deepToString() 方法的工作方式类似于它们那些非深度(non-deep)的同类,但它们不仅会停下手来处理顶级数组的每个元素,还会更深入地研究生成结果的多维数组。

虽然不是一个新方法,但 asList() 方法在 5.0 的工作方式有所不同。以前,这个方法接受 Object[] 数组作为它的参数。现在,因为 Tiger 的可变参数列表特性,任何用逗号分隔的列表都可以接受,如清单 3 所示:


清单 3. Arrays.asList 的区别

 

import java.util.Arrays;

 

public class AsList {

  public static void main(String args[]) {

    // Before

    List before = Arrays.asList(args);

    // After

    List after = Arrays.asList("One", "Two", "Three");

  }

}

 

如果传递给命令行的元素不同,清单 3 中的两个示例没必要产生同样的结果 ,但是它确实展示了 Tiger 在语言级别上的变化如何扩展了 Arrays 原有的 asList() 方法。

 

 

集合

Arrays 用于处理不同集合的辅助类是 Collections 类。同样,这个类也不是一个新类,但是该类的特性已经针对 5.0 作了扩展。现在有 13 个新方法:

  • checkedCollection()
  • checkedSet()
  • checkedSortedSet()
  • checkedList()
  • checkedMap()
  • checkedSortedMap()
  • emptySet()
  • emptyList()
  • emptyMap()
  • reverseOrder()
  • frequency()
  • disjoint()
  • addAll()

其中 6 checked*() 方法工作起来与 6 synchronized*() unmodifiable*() 方法类似。使用 synchronized*() 方法时,要向该方法提供一个集合,然后该方法将返回同一个集合的同步的、线程安全的版本。使用 unmodifiable*() 方法时,得到的是指定集合的只读视图。除了集合参数之外,checked*() 操作可能还要求第二个或者第三个参数(如清单 4 所示),并返回该集合的动态的类型安全视图:


清单 4. 检测后的集合

 

  public static <E> Collection<E> checkedCollection(

    Collection<E> c, Class<E> type)

  public static <E> Set<E> checkedSet(

    Set<E> s, Class<E> type)

  public static <E> SortedSet<E> checkedSortedSet(

    SortedSet<E> s, Class<E> type)

  public static <E> List<E> checkedList(

    List<E> list, Class<E> type)

  public static <K,V> Map<K,V> checkedMap(

    Map<K,V> m, Class<K> keyType, Class<V> valueType)

  public static <K,V> SortedMap<K,V> checkedSortedMap(

    SortedMap<K,V> m, Class<K> keyType, Class<V> valueType)

 

使用 Java 5.0 平台,您可能以为:由于将集合声明为通用集合 Collection<String> c = new HashSet<String>();),所以不需要进行运行时检测了。但是如果向工具方法传递 String 版本的 HashSet,而工具方法只能处理非通用的 Set,那么该方法可能就会错误地向集合添加一个非 String 元素。通过临时修改程序,用 Collection<String> c = Collections.checkedCollection(new HashSet<String>(), String.class); 添加运行时检查,您可以迅速发现问题的根源。

三个 empty*() 方法 —— emptySet()emptyList() emptyMap() —— 生成空的不可改变的集合。虽然也可以用 new ArraySet() 这样的方法创建空集合,但是还要通过某个 unmodifiable*() 方法才能确保新集合是不可改变的。empty 方法用更理想的方式提供了空的只读集合。

 

 

队列(Queue)接口

5.0 集合框架较大的一个改变就是添加了新的基接口 Queue。虽然这个接口是在并发集合技巧 (请参阅 参考资料)中描述的,但它的应用并不限于并发。在计算机科学中,队列数据结构是基本的先进先出(FIFO 结构。项目添加到尾部,并且要从顶部删除。不仅能添加和删除元素,还能查看队列中有哪些元素。清单 5 显示了 Queue 接口的 5 个方法:


清单 5. Queue 接口

 

  public boolean offer(Object element)

  public Object remove()

  public Object poll()

  public Object element()

  public Object peek()

 

请记住,Queue 是从 Collection 接口扩展的,所以实现 Queue 接口也就实现了 Collection。在使用 Queue 的实现时,应当将自己限制在接口的方法上。例如,向 Queue 添加元素可以用 Collection add() 方法来实现,它在失败时会抛出未检测异常。相反,如果大小有限的队列满了,那么 offer() 方法会返回 false,而不需要处理队列满的异常。

java.util.concurrent 包中具有 Queue 接口的多个实现,但并不包含所有实现。LinkedList 类针对 JDK 5.0 Queue 接口作了修正,而 PriorityQueue 是随 JDK 5.0 添加进来的。余下的实现 —— ArrayBlockingQueueConcurrentLinkedQueueDelayQueueLinkedBlockingQueuePriorityBlockingQueue SynchronousQueue —— 都是 java.util.concurrent 包的组成部分。

因为 LinkedList 不是新事物,所以我们来看一下新的 PriorityQueue 类。如清单 6 所示,可以用 6 种方法创建它。在不能使用 Comparator 时,可以使用元素的自然顺序来确定优先级。如果元素没有实现 Comparable 接口,那么就会产生运行时错误:


清单 6. PriorityQueue 构造函数

 

  PriorityQueue()

  PriorityQueue(Collection<? extends E> c)

  PriorityQueue(int initialCapacity)

  PriorityQueue(int initialCapacity, Comparator<? super E> comparator)

  PriorityQueue(PriorityQueue<? extends E> c)

  PriorityQueue(SortedSet<? extends E> c)

 

为了演示 PriorityQueue 的用法,清单 7 中的程序添加了所有命令行元素,并按字母顺序处理它们。由于队列结构是 LinkedList,所以顺序应当是典型的 FIFO 顺序,但是 PriorityQueue 将根据优先级对元素进行排序:


清单 7. PriorityQueue 的用法

 

import java.util.*;

import java.util.concurrent.*;

 

public class Priority {

  public static void main(String args[]) {

    Queue<String> queue =

      new PriorityQueue<String>(Arrays.asList(args));

    String element;

    while ((element = queue.poll()) != null) {

          System.out.println(element);

    }

  }

}

 

清单 8 显示了用命令行 one two three four 运行程序之后的输出


清单 8. 清单 7 的结果

>java Priority one two three four

  four

  one

  three

  two

 

关于新的 Queue 接口,有件事需要提一下,这件事与 Collections 类有关:方法 checkedQueue()emptyQueue()synchronizedQueue() unmodifiableQueue() 全都是 Collections 类中所缺少的。根据 bug 报告,除了 checkedQueue() 之外,所有类都是故意缺失的。对于 synchronizedQueue(),并发集合是比纯粹的包装器更好的选择。其他方法则被认为不是必需的。也许 Tiger/6.0 版本中会添加 checkedQueue()(和 checkedBlockingQueue()  

下载

描述

名字

大小

 下载方法

Sample code

j-tiger07195-source.zip

1 KB

 FTP

   

 

参考资料

  • 您可以参阅本文在 developerWorks 全球站点上的 英文原文
  • 请单击本文顶部或底部的 代码 图标(或请参阅 下载),下载本文所讨论的源代码。
  • 请从 Sun Developer Network 下载 J2SE 5.0
  • 2004 6 月的那期 驯服 Tiger 系列并发集合介绍了阻塞队列和并发映射。请参阅 John Zukowski 撰写的关于将 Java 平台当前版本的大多数内容转变成主要的 驯服 Tiger 系列页面 的技巧。
  • Brian Goetz 撰写的介绍 JDK 5.0 中的泛型developerWorks2004 12 月)介绍了泛型支持上的语言变化。
  • Brian Goetz 撰写的文章了解泛型" developerWorks2005 1 月)解释了使用泛型时一些更容易令人迷惑的方面。
  • 请参阅 java.util 包的 javadoc
  • 请阅读 Sun J2SE 5.0 文档中关于 Lang and Util Enhancements 的内容。
  • 要学习关于 Java 编程的更多内容,请参阅 developerWorks Java 专区。在那里可以找到一些技术文档、how-to 文章、教育、下载、产品信息和其他更多信息。
  • 请参阅 Java 技术新手入门 站点,获得有助于开始 Java 编程的最新参考资料。
  • 通过参与 developerWorks blogs 加入 developerWorks 社区。

 

 

关于作者

John Zukowski JZ Ventures, Inc. 提供战略性 Java 咨询,并与 SavaJe Technologies 合作开发下一代移动电话平台。他的最新力作有 The Definitive Guide to Java Swing, Third EditionApress2005 6 月)和 Mastering Java 2, J2SE 1.4Sybex2002 4 月)。

 

参与评论 您还未登录,请先 登录 后发表或查看评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值