级别: 中级
2008 年 6 月 02 日
Java™ Collections Framework 是 Java 平台的一个重要部分。桌面和企业应用程序通常都使用该框架来聚集集合项。本文将向您展示如何使用集合,同时利用 Java SE 6 中对该框架的增强。通过使用泛型和并发功能使您的应用程序具有更好的维护性和可伸缩性,您可以实现比 HashMap 或 TreeSet 更丰富的功能。
自从最初的 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 所示:
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 GetItException 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。这个异常只会在运行时出现;如果没有进行足够的测试,那么也许直到部署之后才会出现该异常。
现在进入泛型的世界。泛型可以帮助您在开发周期的早期解决编码问题。不只是拥有一个集合并向其中添加 JButton 对象,您可以拥有一个 JButton 对象的集合。然后,如果想要将 JLabel 添加到集合,则编译器会在编译时发现差异和并抛出异常。
在尝试向泛型集合(本例中为 List)添加错误类型的元素时,清单 2 中的程序会生成编译时错误消息:
import java.util.*;import javax.swing.*;
public class GetIt { public static void main(String args[]) {
List buttonList = new LinkedList();
buttonList.add(new JButton("O