Java 教程是为 JDK 8 编写的。本页中描述的示例和实践未利用在后续版本中引入的改进。
JDK 5.0 中的一个变化是类 java.lang.Class
是泛型的。这是一个有趣的例子,它将泛化用于容器类以外的东西。
既然 Class
有一个类型形参 T
,你可能会问,T
代表什么?它代表 Class
对象所代表的类型。
例如,String.class
的类型是 Class<String>
,Serializable.class
的类型是 Class<Serializable>
。这可用于改善反射代码的类型安全性。
特别是,由于 Class
中的 newInstance()
方法现在返回 T
,因此在反射创建对象时可以获得更精确的类型。
例如,假设你需要编写一个执行数据库查询的实用程序方法,以字符串形式给出 SQL ,并返回数据库中与该查询匹配的对象集合。
一种方法是显式传入工厂对象,编写如下代码:
interface Factory<T> { T make();} public <T> Collection<T> select(Factory<T> factory, String statement) { Collection<T> result = new ArrayList<T>(); /* Run sql query using jdbc */ for (/* Iterate over jdbc results. */) { T item = factory.make(); /* Use reflection and set all of item's * fields from sql results. */ result.add(item); } return result; }
你可以这样调用
select(new Factory<EmpInfo>(){ public EmpInfo make() { return new EmpInfo(); }}, "selection string");
或者你可以声明一个类 EmpInfoFactory
来支持 Factory
接口
class EmpInfoFactory implements Factory<EmpInfo> { ... public EmpInfo make() { return new EmpInfo(); } }
并调用它
select(getMyEmpInfoFactory(), "selection string");
该解决方案的缺点是它需要:
将类字面量用作工厂对象是很自然的,然后可以通过反射使用它。今天(没有泛型)代码可能写成:
Collection emps = sqlUtility.select(EmpInfo.class, "select * from emps"); ... public static Collection select(Class c, String sqlStatement) { Collection result = new ArrayList(); /* Run sql query using jdbc. */ for (/* Iterate over jdbc results. */ ) { Object item = c.newInstance(); /* Use reflection and set all of item's * fields from sql results. */ result.add(item); } return result; }
但是,这不会给我们提供我们想要的精确类型的集合。既然 Class
是泛型的,我们可以编写以下内容:
Collection<EmpInfo> emps = sqlUtility.select(EmpInfo.class, "select * from emps"); ... public static <T> Collection<T> select(Class<T> c, String sqlStatement) { Collection<T> result = new ArrayList<T>(); /* Run sql query using jdbc. */ for (/* Iterate over jdbc results. */ ) { T item = c.newInstance(); /* Use reflection and set all of item's * fields from sql results. */ result.add(item); } return result; }
上面的代码以类型安全的方式为我们提供了精确的集合类型。
这种使用类字面量作为运行时类型标记的技术是一个非常有用的技巧。这是一种习惯用法,例如,广泛用于操作注解的新 API 中。