假设我有一个我使用的泛型类,声明如下:
public class ConfigurableRuleKey<R extends Configurable & Rule> extends Key<R> {
private final R rule
public ConfigurableRuleKey(R rule) {
this.rule = rule;
}
/* Additional methods are declared here */
}
我想实现一个工厂方法,在创建可配置规则或创建基本密钥时检查传递的规则是否实现接口Configurable
:
public static <R extends Rule> Key<R> create(R rule) {
if (rule instanceof Configurable) {
return new ConfigurableRuleKey<>(rule); //This will not compile
} else {
return new RuleKey<>(rule);
}
}
问题是在我的工厂方法中我无法将规则传递给ConfigurableRuleKey
的构造函数,因为它不符合声明的泛型约束(如果我明确检查它实现了{{1},则为事件})。问题是如何构建我的规则实例以使它符合Configurable
中的构造函数限制?
答案 0 :(得分:3)
我确实找到了一种方法,可以在不使用原始类型的情况下执行您的要求,但它仍然涉及一对未经检查的强制转换:
@SuppressWarnings("unchecked")
public static <R extends Rule, T extends Rule & Configurable> Key<R> create(R rule) {
if (rule instanceof Configurable) {
return (Key<R>)new ConfigurableRuleKey<>((T)rule);
} else {
return new RuleKey<>(rule);
}
}
我不确定这是否比sp00m的答案好,但至少是不同的。 :)
在Java的泛型中无法正确构造它的内在原因似乎是交集类型需要从具体接口构造,并且不能从其他类型变量构造。因此,在此示例中无法以T
为界限的方式构造R
。如果没有这种能力,甚至没有办法使用类似于Class.asSubclass
的魔术方法来抽象这种行为。
编辑:相关地,Java 8似乎引入了可以转换为多个接口的匿名交集类型 - 例如。 (Configurable & Rule)rule
- 但即使这样做也没有帮助,因为出于与上述相同的原因,您无法转向(Configurable & R)
。然而,它将有助于摆脱类型变量T
:
@SuppressWarnings("unchecked")
public static <R extends Rule> Key<R> create(R rule) {
if (rule instanceof Configurable) {
return (Key<R>)new ConfigurableRuleKey<>((Configurable & Rule)rule);
} else {
return new RuleKey<>(rule);
}
}
答案 1 :(得分:2)
这应该符合您的需求:
@SuppressWarnings({ "rawtypes", "unchecked" })
public static <R extends Rule> Key<R> create(R rule) {
if (rule instanceof Configurable) {
return new ConfigurableRuleKey((Configurable) rule);
} else {
return new RuleKey<>(rule);
}
}
您手动检查rule
是Configurable
,因此演员阵容是安全的。