Ada*_*čík 6 java generics wildcard upperbound
我使用Java 8.在我的设计中,有一些简单的类可以模拟值参数,例如FloatParameter或EnumParameter<E>.A具有这些classes(GenericParameter<T>)的通用超类,它实现了参数名称及其默认值.子类实现了特定于它们的其他属性,例如范围FloatParameter.
此外,我想处理参数的类型,无论其具体类型如何.但是我仍然希望以它们是子类型的方式绑定类型GenericParameter<T>.为了做到这一点,我创建了一个方法,如process(Class<? extends GenericParameter<?>> paramType).
现在的问题是,EnumParameter.class 不能被分配给类型的变量Class<? extends GenericParameter<?>>,而FloatParameter.class 可以是.
此外,我列出了类的代码,使其更清晰,可重复:
public class GenericParameter<T> {
protected String name;
protected T defaultValue;
}
public class FloatGenericParameter extends GenericParameter<Float> {
...
}
public class TypedGenericParameter<T> extends GenericParameter<T> {
...
}
Class<? extends GenericParameter<?>> fgpc = FloatGenericParameter.class; // ok
Class<? extends GenericParameter<?>> tgpc = TypedGenericParameter.class; // error: incompatible types: Class<TypedGenericParameter> cannot be converted to Class<? extends GenericParameter<?>>
Class<? extends GenericParameter> tgpc2 = TypedGenericParameter.class; // warning: [rawtypes] found raw type: GenericParameter
Run Code Online (Sandbox Code Playgroud)
最后,当使用非泛型基类时,没有问题:
public class Parameter {
....
}
public class FloatParameter extends Parameter {
...
}
public class TypedParameter<T> extends Parameter {
...
}
Class<? extends Parameter> fpc = FloatParameter.class; // ok
Class<? extends Parameter> tpc = TypedParameter.class; // ok
Run Code Online (Sandbox Code Playgroud)
拜托,你有什么建议吗?
我可以使用process(Class<?> paramType)变通方法或进行强制转换,但我希望受益于编译器的静态类型检查.
编辑:
我想在注册为每个参数类型生成GUI组件的工厂时使用强制转换.代码如下:
addParameterComponentFactory(EnumParameter.class, new ParameterComponentFactory() { ... })
Run Code Online (Sandbox Code Playgroud)
在这种情况下,编译器将在编译时检查添加的参数类型.代码也会更自我解释.
编辑2:
目前,我正在使用建议的方法为该方法引入类型参数addParameterComponentFactory.签名如下所示:
public static <P extends GenericParameter<?>> addParameterComponentFactory(Class<P> clazz, ParameterComponentFactory pcf)
Run Code Online (Sandbox Code Playgroud)
通过这个定义,我可以指定TypedParameter.class(EnumParameter.class- 也是一个类型参数)以及我获得静态类型检查.
让我们从 API 的核心部分开始。您有一个泛型Parameter<T>
类型,它表示某个值为 type 的命名参数T。您有专门的 GUI 组件,旨在编辑或显示特定类型的参数,并且您希望能够注册工厂来创建这些组件。
class Parameter<T> {
String name;
T defaultValue;
}
class ParameterComponent<P extends Parameter> {
void setParameter(final P p) {}
}
interface ParameterComponentFactory<P extends Parameter> {
ParameterComponent<P> newComponent();
}
class FloatParameter extends Parameter<Float> {}
class FloatParameterComponent extends ParameterComponent<FloatParameter> {}
class EnumParameter extends Parameter<Enum> {}
class EnumParameterComponent extends ParameterComponent<EnumParameter> {}
Run Code Online (Sandbox Code Playgroud)
Parameter如果我理解正确的话,那么您在弄清楚如何声明一个方法来静态地强制某种类型与专门用于该类型的 GUI 组件的工厂之间的关系时遇到了麻烦
。例如,您希望能够这样写:
addComponentFactory(EnumParameter.class, EnumParameterComponent::new); // OK
addComponentFactory(FloatParameter.class, FloatParameterComponent::new); // OK
addComponentFactory(FloatParameter.class, EnumParameterComponent::new); // ERROR!
Run Code Online (Sandbox Code Playgroud)
该问题与通用子类型的规则有关,您可以通过使用类型变量而不是嵌入的通配符来解决它们。这应该可以为您提供所需的类型检查,而无需进行令人讨厌的转换:
static <P extends Parameter> void addComponentFactory(
final Class<P> parameterType,
final ParameterComponentFactory<? extends P> factory) { ... }
Run Code Online (Sandbox Code Playgroud)
P extends Parameter<?>解释引入新类型Class<P>和直接声明之间的区别Class<? extends Parameter<?>>
这很复杂,所以请耐心等待。我们来谈谈通配符、原始类型和转换。考虑以下:
// Scenario 1(a)
GenericParameter raw = /* some value */;
GenericParameter<?> wc = raw;
// Scenario 1(b)
Class raw = GenericParameter.class;
Class<?> wc = raw;
// Scenario 2
Class<GenericParameter> classOfRaw = GenericParameter.class;
Class<GenericParameter<?>> classOfWC = classOfRaw;
Run Code Online (Sandbox Code Playgroud)
场景 1(a) 和 1(b) 都出于相同的原因进行编译:因为原始类型
G可能会经过未经检查的转换
为任何形式的参数化类型G<T_1, ..., T_n>。
场景 2 无法编译。但为什么?
在场景 2 中,第二个赋值中的双方都不是原始类型。为了使 赋值有效,必须存在 从右手类型到左手类型的恒等转换或扩大转换。对于引用类型的扩展转换,左侧类型必须是右侧类型的超类型。当这些类型是通用类型时,适用通用子类型规则 。具体来说,左侧的类型参数必须 包含 右侧的类型参数。
Class<String>从到 的分配Class<? extends Object>是有效的。
是because
containsClass<String>的通用子类型。在场景 2 中,要使第二个赋值有效,必须包含
,但事实并非如此。 不是;
的子类型 是 的超类型。因此,根据通用子类型规则,
不是 的子类型,并且赋值无效。Class<? extends Object>? extends Object StringGenericParameter<?>GenericParameterTT<?>TT<?>Class<T>Class<T<?>>
那么为什么下面的方法有效呢?
public static <P extends GenericParameter<?>> addParameterComponentFactory(
Class<P> clazz,
ParameterComponentFactory pcf)
addParameterComponentFactory(EnumParameter.class, new ParameterComponentFactory() {})
Run Code Online (Sandbox Code Playgroud)
在上面的调用中,类型推断P完全由参数驱动
Class<P>。您正在传递 a Class<EnumParameter>,因此P
在这种情况下会绑定到原始类型EnumParameter。P extends GenericParameter<?>为了满足约束
,GenericParameter<?>
必须可从 进行分配EnumParameter,并且可通过未经检查的转换进行分配,就像场景 1(a) 和 1(b) 中一样。
[1]这个解释是公然抄袭,是 Stack Overflow 上其他优秀答案(主要是radiodef
的答案)的合并
。
| 归档时间: |
|
| 查看次数: |
826 次 |
| 最近记录: |