类 Literals 作为运行时类型令牌

JDK 5.0 中的更改之一是类java.lang.Class是通用的。这是一个对容器类以外的东西使用泛型的有趣示例。

现在Class具有类型参数T,您可能会问T代表什么?它代表Class对象表示的类型。

例如,String.class的类型是Class<String>,而Serializable.class的类型是Class<Serializable>。这可以用来提高反射代码的类型安全性。

特别是,由于Class中的newInstance()方法现在返回T,因此在反射性创建对象时可以获得更精确的类型。

例如,假设您需要编写一个 Util 方法来执行数据库查询(以 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以支持Factoryinterface

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

叫它

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

该解决方案的缺点是它需要:

  • 在呼叫站点使用冗 Long 的匿名工厂类,或者

  • 为每种使用的类型声明一个工厂类,并在调用站点传递一个工厂实例,这有点不自然。

将类 Literals 用作工厂对象是很自然的,然后可以通过反射使用它。今天(没有泛型),代码可能被编写为:

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是通用的,我们可以 Rewrite 以下内容:

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

上面的代码以类型安全的方式为我们提供了精确的集合类型。

使用类 Literals 作为运行时类型标记的这种技术是一个非常有用的技巧。例如,它是一种新用法,在新的 API 中广泛使用来处理 注解。