我有一个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
参数而不是枚举。这将至少提供一些编译时保证,即类令牌适合于生成的结果列表的类型。但是,这仍然无法使用枚举中的数据;我还是要在方法调用之前抛出它。
我可以使用支票吗?
=============================================== ===
更新12/6/14
在我看来,如果没有一个好的,干净的解决方案,这是一个问题。
枚举不支持泛型类型参数(它们不能)。
每次尝试在枚举常量中存储参数化类型时,都会在编译时出现不兼容的类型信息。
使用参数化的类型安全单例模式,如建议的那样,将使编译器能够检查类型安全性,但我拥有的API已经渗透到这些枚举类中,我觉得我不能将它们重构为常规类。< / p>
为了限制损害,我想知道以下推理是否准确:
与枚举常量相关的数据是静态的和最终的;这里也是一成不变的。
我完全控制进入枚举常量的数据,所以我在运行时知道e_tbl
字段永远是Class
某个类型的Row
对象,它扩展了{{ 1}}。
这些假设承认我认为有两个方法具有相同的缺陷。在枚举类中,访问器方法被重写为:
@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常量或结果将是“未定义”之外,还有任何方法可以控制此。
由于枚举不适用于泛型类型,我认为没有更好的解决方案。
答案 0 :(得分:2)
你可以做的一件事:
TableMetaData
转为TableMetaData<E>
,并根据E
enum
(因为它们不支持类型参数)并编写一个类
每个枚举条目因此界面看起来大致像
class Histories implements TableMetaData<SpecialRowType> {
Class<SpecialRowType> modelClass();
}
最终允许你施放使用它。
static final <E extends Row> List<E> doQuery (
final List<JdbcValue> pars,
final String sql,
final TableMetaData<E> dm
)
{
List<E> result = new ArrayList<E>();
// type safe, because E refers to the same thing.
Class<E> cls = dm.modelClass();
:
}
现在编译器可以确保? extends Row
类与E extends Row
类相同,它具有共同的祖先,但这并不意味着您可以将它们相互转换。