我对这段代码有疑问。当我想插入Map EnumElement使用者时,它无法编译并显示错误error: type argument Enum is not within bounds of type-variable T
。问题是我不能更改* Value类。有办法使它工作吗?
import java.util.*;
import java.util.function.*;
public class Main {
public static void main(String[] args) {}
private static final Map<Class<?>, Consumer<Element>> CONFIG_ELEMENTS = new HashMap<>();
static {
CONFIG_ELEMENTS.put(BooleanValue.class, element -> new BooleanElement((ConfigElement<Boolean, BooleanValue>) element));
// CONFIG_ELEMENTS.put(EnumValue.class, element -> new EnumElement<>((ConfigElement<Enum, EnumValue<Enum>>) element)); // doesn't compile
}
private static class ConfigValue<T>{}
private static class BooleanValue extends ConfigValue<Boolean> {}
private static class EnumValue<T extends Enum<T>> extends ConfigValue<T> {}
private static class Element{}
private static class ConfigElement<S, T extends ConfigValue<S>> extends Element {}
private static class BooleanElement extends ConfigElement<Boolean, BooleanValue> {
BooleanElement(ConfigElement<Boolean, BooleanValue> value) {}
}
private static class EnumElement<T extends Enum<T>> extends ConfigElement<T, ConfigValue<T>> {
EnumElement(ConfigElement<T, ConfigValue<T>> value) {}
}
}
答案 0 :(得分:1)
...有办法使它工作吗?...
我得到了您的例子working this way:
public <V, U extends ConfigValue<V> >EnumElement(ConfigElement<V, U> value){}…
…new EnumElement((ConfigElement<? extends Enum<?>, EnumValue<? extends Enum<?>>>) element )…
我在您的几个类中添加了一些基本实现,以确认该解决方案是否可用:
…
static public void main( String ...args ){
EnumValue< Foo > ev = new EnumValue< >( );
ConfigElement< Foo, EnumValue< Foo > > ce = new ConfigElement< >( );
EnumElement< Foo > ee = new EnumElement< >( ce );
ee.setE( Foo.BAR );
Foo bar = ee.getE( );
out.println( bar );
Consumer< Element > c = CONFIG_ELEMENTS.get( ev.getClass( ) );
c.accept(ee);
}
…
如果要检查它是否可以编译并运行,请单击上面链接中在线IDE项目顶部的绿色 开始 按钮。
答案 1 :(得分:0)
首先让我们澄清一些事情。您的第一个CONFIG_ELEMENTS.put...
等同于(只需确保您理解即可)。
CONFIG_ELEMENTS.put(
BooleanValue.class,
element -> {
new BooleanElement((ConfigElement<Boolean, BooleanValue>) element);
return;
}
);
现在您声明的CONFIG_ELEMENTS
映射知道它所持有的值是Element
类型,即上面的值可以写为:
CONFIG_ELEMENTS.put(
BooleanValue.class,
(Element element) -> {
new BooleanElement((ConfigElement<Boolean, BooleanValue>) element);
return;
}
);
这就是为什么要做这项工作的唯一方法是投射那个element
的原因;因为它的类型为Element
,但是您的BooleanElement
采用ConfigElement
作为输入。这应该很明显。
第二个CONFIG_ELEMENTS.put...
解释必须以此开头:
private static class EnumElement<T extends Enum<T>> extends ConfigElement<T, ConfigValue<T>> {
EnumElement(ConfigElement<T, ? extends ConfigValue<T>> value) {
}
}
注意? extends ConfigValue<T>> value
部分。您需要这样做,因为generics are invariant,因此为了能够传递扩展了ConfigValue
的内容,您需要正确地声明参数类型。
其余的解释是我纯粹的有根据的猜测,因为我并没有真正理解这里发生的事情(我有一些暗示,这与使用原始类型以及T
有关EnumElement
中的变量和T
中的EnumValue
是不同的类型变量)...
IMO,最简单的方法是更改此内容:
private static class EnumValue<T extends Enum> extends ConfigValue<T> {}
使用原始Enum
。
编辑
以下是评论中要求的完整示例:
public class DeleteMe {
private static final Map<Class<?>, Consumer<Element>> CONFIG_ELEMENTS = new HashMap<>();
static {
CONFIG_ELEMENTS.put(BooleanValue.class, element -> new BooleanElement((ConfigElement<Boolean, BooleanValue>) element));
CONFIG_ELEMENTS.put(EnumValue.class,
element -> new EnumElement<>((ConfigElement<Enum, EnumValue<Enum>>) element)); // doesn't compile
}
private static class BooleanValue extends ConfigValue<Boolean> {}
private static class BooleanElement extends ConfigElement<Boolean, BooleanValue> {
BooleanElement(ConfigElement<Boolean, BooleanValue> value) {}
}
private static class ConfigValue<T> {
}
private static class EnumValue<TT extends Enum> extends ConfigValue<TT> {}
private static class Element {}
private static class ConfigElement<S, T extends ConfigValue<S>> extends Element {}
static class EnumElement<T extends Enum<T>> extends ConfigElement<T, ConfigValue<T>> {
EnumElement(ConfigElement<T, ? extends ConfigValue<T>> value) {
}
private T e;
public void setE(T e) { this.e = e; }
public T getE() { return e; }
}
static public void main(String... args) {
EnumValue<Foo> ev = new EnumValue<>();
ConfigElement<Foo, EnumValue<Foo>> ce = new ConfigElement<>();
EnumElement<Foo> ee = new EnumElement<>(ce);
ee.setE(Foo.BAR);
Foo bar = ee.getE();
System.out.println(bar);
Consumer<Element> c = CONFIG_ELEMENTS.get(ev.getClass());
c.accept(ee);
}
enum Foo {
BAR
}
}