Documentation

The Java™ Tutorials
Hide TOC
Class Literals as Runtime-Type Tokens将文本类作为运行时类型标记
Trail: Bonus
Lesson: Generics

Class Literals as Runtime-Type Tokens将文本类作为运行时类型标记

One of the changes in JDK 5.0 is that the class java.lang.Class is generic. JDK 5.0中的一个变化是java.lang.Class类泛型的。It's an interesting example of using genericity for something other than a container class.这是一个有趣的例子,它将泛型用于容器类以外的其他对象。

Now that Class has a type parameter T, you might well ask, what does T stand for? 现在这个Class有了一个类型参数T,你可能会问,T代表什么?It stands for the type that the Class object is representing.它代表Class对象所代表的类型。

For example, the type of String.class is Class<String>, and the type of Serializable.class is Class<Serializable>. 例如,String.class的类型是Class<String>Serializable.class的类型是Class<Serializable>This can be used to improve the type safety of your reflection code.这可以用来提高反射代码的类型安全性。

In particular, since the newInstance() method in Class now returns a T, you can get more precise types when creating objects reflectively.特别是,由于Class中的newInstance()方法现在返回一个T,所以在反射式创建对象时可以获得更精确的类型。

For example, suppose you need to write a utility method that performs a database query, given as a string of SQL, and returns a collection of objects in the database that match that query.例如,假设您需要编写一个实用程序方法来执行数据库查询(以SQL字符串形式给出),并返回数据库中与该查询匹配的对象集合。

One way is to pass in a factory object explicitly, writing code like:一种方法是显式传入factory对象,编写如下代码:

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;
}

You can call this either as你可以用这种方式调用它

select(new Factory<EmpInfo>(){ 
public EmpInfo make() {
return new EmpInfo();
    }}, "selection string");

or you can declare a class EmpInfoFactory to support the Factory interface或者可以声明一个类EmpInfoFactory来支持Factory接口

class EmpInfoFactory implements Factory<EmpInfo> {
    ...
public EmpInfo make() {
return new EmpInfo();
    }
}

and call it也可以用这种方式调用它

select(getMyEmpInfoFactory(), "selection string");

The downside of this solution is that it requires either:这种解决方案的缺点是需要:

It is natural to use the class literal as a factory object, which can then be used by reflection. 将类字面量用作工厂对象是很自然的,然后反射就可以使用它。Today (without generics) the code might be written:今天(没有泛型),代码可能是这样写的:

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;
}

However, this would not give us a collection of the precise type we desire. 然而,这并不能提供我们想要的精确类型的集合。Now that Class is generic, we can instead write the following:既然该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;
}

The above code gives us the precise type of collection in a type safe way.上面的代码以类型安全的方式为我们提供了精确的集合类型。

This technique of using class literals as run time type tokens is a very useful trick to know. 这种将类文本用作运行时类型标记的技术是一个非常有用的技巧。It's an idiom that's used extensively in the new APIs for manipulating annotations, for example.例如,这是一个在新的API中广泛使用的用于操作注释的习惯用法。


Previous page: The Fine Print
Next page: More Fun with Wildcards