Java™ 5 扩展了 Java 语言类型系统以支持类、方法和值的参数化类型。参数化的类型通过确保使用正确的类型及消除从源代码进行类型转换提供了重要的编译时好处。除了这些编译时好处,类型信息对于 classworking 工具操纵 Java 代码也有帮助。在本文中,JiBX 首席开发员 Dennis Sosnoski 分析了如何用反射深入参数化类型的内部,并充分展示了 Java 5 应用程序数据结构的优势。
许多工具都是围绕使用 Java 反射而设计的,它们的用途包括从用数据值填充 GUI 组件到在运行的应用程序中动态装载新功能。反射对于在运行时分析数据结构非凡有用,许多在内部对象结构与外部格式(包括 XML、数据库和其他持久化格式)之间转换的框架都基于对数据结构的反射分析。
使用反射分析数据结构的一个问题是标准 Java 集合类(如 java.util.ArrayList)对于反射来说总是“死胡同(dead-end)” —— 到达一个集合类后,无法再访问数据结构的更多细节,因为没有关于集合中包含的项目类型的信息。Java 5 改变了这一情况,它增加了对泛型的支持,将所有集合类转换为支持类型的泛型形式。Java 5 还扩展了反射 API ,支持在运行时对泛型类型信息进行访问。这些改变使反射可以比以往更深入地挖掘数据结构。
包装之下代码
许多文章讨论了 Java 5 的泛型功能的使用。对于本文,假定您已经了解泛型的基本知识。我们首先使用一些示例代码,然后直接讨论如何在运行时访问泛型信息。
作为使用泛型的一个例子,我预备使用一个表示一组路径中的目录和文件的数据结构。清单 1 给出了这个数据结构根类的代码。PathDirectory 类取路径 String 数组作为构造函数参数。这个构造函数将每一个字符串解释为目录路径,并构造一个数据结构以表示这个路径下面的文件和子目录。处理每一路径时,这个构造函数就将这个路径和这个路径的数据结构加到一个成对集合(pair collection)中。
清单 1. 目录信息集
public class PathDirectory implements Iterable
{
private final PairCollection m_pathPairs;
public PathDirectory(String[] paths) {
m_pathPairs = new PairCollection();
for (String path : paths) {
File file = new File(path);
if (file.exists() && file.isDirectory()) {
DirInfo info = new DirInfo(new File(path));
m_pathPairs.add(path, info);
}
}
}
public PairCollection.PairIterator iterator() {
return m_pathPairs.iterator();
}
public static void main(String[] args) {
PathDirectory inst = new PathDirectory(args);
PairCollection.PairIterator iter = inst.iterator();
while (iter.hasNext()) {
String path = iter.next();
DirInfo info = iter.matching();
System.out.println("Directory " + path + " has " +
info.getFiles().size() + " files and " +
info.getDirectories().size() + " child directories");
}
}
}
清单 2 给出了 PairCollection 的代码。这个泛型类处理成对的值,类型参数给出了这些对中项目的类型。它提供了一个 add() 方法向集合中加入一个元组(tuple),一个 clear() 方法清空集合中所有元组,一个 iterator() 方法返回遍历集合中所有对的迭代器。内部 PairIterator 类实现由后一个方法返回的非凡迭代器,它定义了一个额外的 matching() 方法,这个方法用于得到由标准 next() 方法返回的值的配对(第二个)值。
清单 2. 泛型对集合
public class PairCollection implements Iterable
{
// code assumes random Access so force implementation class
private final ArrayList m_tValues;
private final ArrayList m_uValues;
public PairCollection() {
m_tValues = new ArrayList();
m_uValues = new ArrayList();
}
public void add(T t, U u) {
m_tValues.add(t);
m_uValues.add(u);
}
public void clear() {
m_tValues.clear();
m_uValues.clear();
}
public PairIterator iterator() {
return new PairIterator();
}
public class PairIterator implements Iterator
{
private int m_offset;
public boolean hasNext() {
return m_offset < m_tValues.size();
}
public T next() {
if (m_offset < m_tValues.size()) {
return m_tValues.get(m_offset++);
} else {
throw new NoSUChElementException();
}
}
public U matching() {
if (m_offset > 0) {
return m_uValues.get(m_offset-1);
} else {
throw new NoSuchElementException();
}
}
public void remove() {
throw new UnsupportedOperationException();
}
}
}