泛型Java:如何从<>实现动态转换?扩展…>到<E>
我有一个enum
存储数据库表的一些元数据:
static enum DataTable implements TableMetaData {
HISTORIES ("h", Hx.class, HxColumn.HPI_ID),
:
:
private final String e_alias;
private final Class<? extends Row> e_tbl;
private final ColumnMetaData e_idCol;
DataTable(String al,
Class <? extends Row> c1,
ColumnMetaData id)
{...}
@Override public Class<? extends Row> modelClass() { return this.e_tbl; }
:
:
}
感兴趣的字段是e_tbl
,它存储与数据库表对应的模型对象类。此项目中的所有模型对象类都实现了Row
接口。我希望能够访问此字段以生成此类的实例
我的问题是,我使用的是一个未经检查的强制转换,我不知道它是否安全,而且我还没有弄清楚如何执行运行时检查以确保模型对象匹配。以下是发生强制转换的代码:
static final <E extends Row> List<E> doQuery (
final List<JdbcValue> pars,
final String sql,
final TableMetaData dm
)
{
List<E> result = new ArrayList<E>();
@SuppressWarnings("unchecked")
Class<E> cls = (Class<E>) dm.modelClass();
:
:
}
我认为这是一个危险的演员阵容。该查询旨在生成E
实例,这些实例将使用提供的枚举常量中包含的模型类生成。问题是我无法知道E
与枚举中存储的类标记匹配。在这种情况下Class.asSubclass()
似乎无法帮助我
问题是我有一个字段是<? extends Row>
,我需要使它与<E extends Row>
兼容
一种解决方案是将方法重构为需要Class<E> cls
参数而不是枚举。这将至少提供一些编译时保证,即类标记适合生成的结果列表的类型。但是,这仍然不能使我使用枚举中的数据;我仍然必须在方法调用之前强制转换它
有支票我可以用吗
==================================================
于2014年6月12日更新
在我看来,这是一个没有好的、干净的解决方案的问题
枚举不支持泛型类型参数(它们不能)
每次尝试在枚举常量中存储参数化类型时,编译时都会出现不兼容的类型信息
正如建议的那样,使用参数化的类型安全单例模式将使编译器能够检查类型安全性,但我拥有的API被这些枚举类所渗透,我觉得我无法将它们重构为常规类
为了限制损失,我想知道以下推理是否准确:
与枚举常量关联的数据是静态的和最终的;在这里,它也是不变的
我完全控制进入枚举常量的数据,因此在运行时我知道
e_tbl
字段将始终是某种类型的Class
对象,它扩展了Row
这些假设承认了我认为具有相同缺陷的两种方法。在enum类中,访问器方法重写为:
@Override public <E extends Row> Class<E> modelclass() {
@SuppressWarning("unchecked")
Class<E> cls = (Class<E>) this.e_tbl;
return this.e_tbl; }
我可以将枚举中的数据存储到使用原始类型的字段中。原始类型与泛型访问器方法互操作,因此它会编译,但会生成警告
我可以将枚举中的数据存储到使用
<? extends Row>
通配符类型的字段中。这不会使用泛型访问器方法(<E> extends Row>
)编译,因此我必须使用未经检查的强制转换。仍会生成警告
因为我知道枚举数据总是扩展Row
,所以我认为这可能是可以的。我不能保证所检索的枚举数据适合于所生成的List
类型。但我认为除了记录API用户必须为返回的查询发送正确的TableMetaData常量,否则结果将是“未定义”的之外,没有任何方法可以对此进行控制
由于枚举不能处理泛型类型,我认为没有更好的解决方案
# 1 楼答案
你可以做一件事:
TableMetaData
变成TableMetaData<E>
,并根据E
定义类enum
(因为它们不支持类型参数),编写一个类 每个枚举条目所以界面看起来大致像
这样你就可以使用它了
现在,编译器可以确保
? extends Row
类与E extends Row
类相同,它们确实有一个共同的祖先,但这并不意味着可以将它们相互转换