自从最初的 Java 2 platform, Version 1.2 发布以后,Java Collections Framework 一直在不断发展。在 Java SE 5 中,泛型的引入增强了框架, java.util.concurrent 的引入添加了对并发的直接支持(请参阅 参考资料)。 在 Java SE 6 中,框架中添加了更好的双向集合访问特性。本文将向您介绍集 合库的所有这些方面,并帮助您利用与并发相关的流行功能。
本文的高级任务是创建一个 Web crawler:给定一个网站的基 URL,从该网 站收集可以用作某种用途的元素。您将从单个网页收集一系列链接,然后蔓延到 整个网站。把高级任务分解为子任务,这些子任务可以转化为自己的作业。您将 了解并使用泛型和线程池。为了使任务更加简单,我们将任务作为独立的客户端 应用程序实现。(解释如何部署 Web 应用程序并不是本文的中心目的。但是可 以随意创建一个 Web 应用程序,将任务作为附加的练习在此应用程序中启动。 )
您应该熟悉 Java 平台上的程序开发。本文假设您熟悉连网和 I/O 库,这两 方面知识将分别用于 socket 连接和读取流。您需要安装一个开发人员版本的 Java SE 6 平台。它至少应该是来自 Sun Microsystems 的 Update 5 of JDK 6 或来自 IBM 的 最新的 SDK for Java, Version 6。
了解泛型
从 Java SE 5 版本开始,泛型的概念就成为了 Java 平台的一部分(请参阅 参考资料)。简单来说,泛型为集合提供了编译时类型安全。在早期的 Java 平 台版本中,您创建一个集合,并向其中添加项,如清单 1 所示:
清单 1. 向集合添加项 — 旧方法
List buttonList = new LinkedList();
buttonList.add(new JButton("One"));
buttonList.add(new JButton("Two"));
buttonList.add(new JButton("Three"));
buttonList.add(new JButton("Four"));
要从集合中提取元素,您必须知道集合中对象的类型,以将其强制转换为合 适的局部变量:
JButton first = (JButton)buttonList.get(0);
您并不需要 将其强制转换为正确的类型,但是如果您想要对某个特定类类型 进行操作,则需要这么做。这种方法运行得很好,除非您不小心向集合中添加了 错误的类型对象:
buttonList.add(new JLabel("Five"));
现在,如果您尝试将最后一个元素作为 JButton 来提取,则在运行时会出现 一个类转换异常:
Line 13: JButton last = (JButton)buttonList.get(4);
>java GetIt
Exception in thread "main" java.lang.ClassCastException:
javax.swing.JLabel cannot be cast to javax.swing.JButton
at GetIt.main(GetIt.java:13)
在本质上,将 JLabel 放入集合并没有任何问题,但是如果提取代码希望集 合中的所有元素都是同一类型(这里为 JButton),那么从集合中提取一个 JLabel 就会生成 ClassCastException。这个异常只会在运行时出现;如果没有 进行足够的测试,那么也许直到部署之后才会出现该异常。