我有两个实现一些通用接口的枚举,我想从该方法返回类文字。但是我无法正确指定交集类型。请参阅下面的说明问题的代码示例。
public class GenericsTest {
interface Iface {
}
enum E1 implements Iface {
}
enum E2 implements Iface {
}
<E extends Enum<E> & Iface> Class<E> getEnum1() {
return E1.class; //ERROR incompatible types: java.lang.Class<GenericsTest.E1> cannot be converted to java.lang.Class<E>
}
Class<? extends Enum<?>> getEnum3() {
return E1.class; //OK
}
Class<? extends Iface> getEnum4() {
return E1.class; //OK
}
<E extends Enum<E> & Iface> void enumParam(Class<E> p) {
enumParam(E1.class); //OK
}
}
#getEnum1
方法无法编译。有趣的是,它在#enumParam
中作为参数值起作用。如何指定交集类型以便能够从方法返回类文字?
答案 0 :(得分:2)
方法getEnum1
的编译方式与此完全相同:
public <E> E foo() {
return "bar"; // Compile time error: Incompatible types E and String
}
请参阅?仅仅因为类型参数E
最终可能是一个字符串,并不意味着它与<{1}} 兼容。可以将此函数称为String
,因此返回字符串在这里没有意义。
Integer i = x.<Integer>foo();
完全相同。类型参数getEnum1
可以选择为E
类型(此处命名非常糟糕),但这并不意味着E1
始终与E1
兼容。考虑E
。您可能想知道为什么编译器只会在尝试使用错误的类型参数调用错误时警告错误。问题是,E2 e2 = x.<E2>getEnum1();
满足类型约束,因此没有理由在那里显示错误。
最简单(也可能是唯一)的方法是在那里摆脱泛型:
E2
如果你不想在这里公开具体类型Class<E1> getEnum1() {
return E1.class;
}
,那你就不走运了。您所能做的就是将常用功能提取到接口,并返回该类型。
答案 1 :(得分:1)
这里的问题是,鉴于每次使用的上下文,您的代码无法保证返回正确的类类型实例。 E.g。
final Class<E2> e2var = new GenericsTest().getEnum1();
编译器在getEnum1
处失败,以防止有人试图对e2var引用的对象执行E2
绑定操作时出现延迟的运行时错误,实际上始终为Class<E1>
。
要提出解决方案,您需要更具体地说明此类集的预期用途。
相反,enumParam
的工作原理并不奇怪,因为它不需要返回匹配的类对象。然而,很明显它会因无限递归而导致堆栈溢出。