我使用Java 8.在我的设计中,有一些简单的类可以为FloatParameter
或EnumParameter<E>
等值参数建模。 A具有这些类(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
最后,当使用非泛型基类时,没有问题:
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
请你有什么建议吗?
我可以使用process(Class<?> paramType)
作为解决方法或进行强制转换,但我希望受益于编译器的静态类型检查。
编辑:
我想在注册为每个参数类型生成GUI组件的工厂时使用强制转换。代码如下:
addParameterComponentFactory(EnumParameter.class, new ParameterComponentFactory() { ... })
在这种情况下,编译器会在编译时检查添加的参数类型。此外,代码将更加自我解释。
编辑2:
目前,我正在使用建议的方法为addParameterComponentFactory
方法引入类型参数。签名如下所示:
public static <P extends GenericParameter<?>> addParameterComponentFactory(Class<P> clazz, ParameterComponentFactory pcf)
使用此定义,我可以指定TypedParameter.class
(EnumParameter.class
- 也是一种类型参数)以及获取静态类型检查。
答案 0 :(得分:1)
让我们从API的核心位开始。你有一个通用Parameter<T>
表示某个命名参数的类型,其值为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> {}
如果我理解正确,你就会遇到麻烦
声明一种静态强制某些关系的方法
Parameter
类型和专门用于该类型的GUI组件的工厂。
例如,您希望能够写下这个:
addComponentFactory(EnumParameter.class, EnumParameterComponent::new); // OK
addComponentFactory(FloatParameter.class, FloatParameterComponent::new); // OK
addComponentFactory(FloatParameter.class, EnumParameterComponent::new); // ERROR!
问题与通用子类型的规则有关,您可以通过使用类型变量而不是嵌入式通配符来解决它们。这应该为您提供所需的类型检查,而无需 讨厌的演员:
static <P extends Parameter> void addComponentFactory(
final Class<P> parameterType,
final ParameterComponentFactory<? extends P> factory) { ... }
解释引入
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;
方案1(a)和1(b)都编译原因相同:因为原始类型
G
可能会G<T_1, ..., T_n>
到Class<String>
形式的任何参数化类型。
场景2执行 NOT 编译。但为什么呢?
在场景2中,第二个分配中的任何一方都不是原始类型。为了 unchecked conversion, 必须有身份转换或assignment to be valid 从右手型到左手型。用于扩大转换次数 引用类型,左手类型必须是右手类型的超类型。 当这些类型是通用的时,widening conversion的规则 应用。具体来说,左侧的类型参数必须 generic subtyping 右侧的类型参数。
从Class<? extends Object>
到Class<String>
的作业有效。
Class<? extends Object>
是? extends Object
的通用子类型,因为
String
包含 GenericParameter<?>
。在场景2中,第二个
赋值有效,GenericParameter
必须包含
T
,但事实并非如此。 T<?>
不是T
的子类型;
T<?>
是Class<T>
的超类型。因此,通过通用子类型规则,
Class<T<?>>
不是public static <P extends GenericParameter<?>> addParameterComponentFactory(
Class<P> clazz,
ParameterComponentFactory pcf)
addParameterComponentFactory(EnumParameter.class, new ParameterComponentFactory() {})
的子类型,而分配则不是
有效的。
那么为什么以下工作呢?
P
在上面的调用中,Class<P>
上的类型推断完全由。{
Class<EnumParameter>
论点。您正在传递P
,因此EnumParameter
在这种情况下,绑定到原始类型P extends GenericParameter<?>
。对于约束
要GenericParameter<?>
满意,EnumParameter
必须可以从NULL
分配,并且可以通过分配
未经检查的转换,就像在场景1(a)和1(b)中一样。
[1] 这个解释是明目张胆的加勒比主义
其他出色的Stack Overflow答案的合并,主要是由
contain 子>