错误:类型参数Enum不在类型变量T的范围内

时间:2020-07-06 21:05:29

标签: java generics

我对这段代码有疑问。当我想插入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) {}
    }
}

2 个答案:

答案 0 :(得分:1)

...有办法使它工作吗?...

我得到了您的例子working this way

  1. public <V, U extends ConfigValue<V> >EnumElement(ConfigElement<V, U> value){}…
  2. …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
    }

}