服务热线:13616026886

技术文档 欢迎使用技术文档,我们为你提供从新手到专业开发者的所有资源,你也可以通过它日益精进

位置:首页 > 技术文档 > JAVA > 新手入门 > 基础入门 > 查看文档

驯服tiger(j2se5.0)之集合框架


  您可能已经非常熟悉新的j2se5.0语言的泛型支持、并发工具库以及它们对集合框架的影响,但是这些并不是j2se5.0中集合框架的惟一变化。本文将介绍另外几项增强,其中包括新的集合类型,以及现有类和接口的附加特性。

  jdk 5.0 中最吸引人的地方在于集合框架的一些最突出的特性上,例如:支持泛型的语言级别上的新变化,以及可以在 java.util.concurrent 包中找到的并发集合工具包。在本文中,我将研究其他三个变化:更新过的 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 添加进来的。余下的实现 ―― arrayblockingqueue、concurrentlinkedqueue、delayqueue、linkedblockingqueue、priorityblockingqueue 和 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(),并发集合是比纯粹的包装器更好的选择。其他方法则被认为不是必需的。也许新版本中会添加 checkedqueue()(和 checkedblockingqueue()) 。

扫描关注微信公众号