有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java枚举。valueOf为扩展枚举的未知类类型引发警告?

给这个:

Class<? extends Enum> enumClass = ...; // being passed in from a constructor
Enum e = Enum.valueOf(enumClass, aString); // produces a warning that looks like

[unchecked] unchecked method invocation: valueOf(java.lang.Class,java.lang.String) in java.lang.Enum is applied to (java.lang.Class,java.lang.String)

我不想使用泛型,因为这是一个重大变化。我不想压制。我不明白为什么会出现这种警告。我想这是因为无法扩展枚举类型。我明白了。但我不明白为什么通配符类会抛出这个奇怪的错误。有没有办法不使用@SupressWarning或泛型来解决这个问题

编辑:为了澄清,下面使用泛型的代码会消除警告

class Foo<T extends Enum<T>>{
    Class<T> enumClass;
    Enum e = Enum.valueOf(enumClass, aString);
}

我所说的泛型就是<T>的用法。我不能这么做,因为这将是一个巨大的级联变化


共 (3) 个答案

  1. # 1 楼答案

    如果您考虑valueOf内部必须发生的事情,您将意识到您的代码不可能像编写的那样工作。枚举。valueOf需要实际枚举类的实例作为参数;然后,它只是在该类的values()中迭代,寻找匹配项

    由于type erasure,泛型在代码中不起作用。没有实际类型被传递到Enum.valueOf

  2. # 2 楼答案

    EnumClass都是泛型的。所以如果你不想要任何警告:

    class Foo<T extends Enum<T>>{
        Class<T> enumClass;
        T e = Enum.valueOf(enumClass, str);
    }
    

    或者你可以有一个通用的方法:

    public <T extends Enum<T>> T getEnumValue(Class<T> clazz, String name) {
        T e = Enum.valueOf(clazz, name);
        return e;
    }
    

    但如果不使用泛型,则使用的是原始类型,因此编译器会发出警告——除了抑制它们之外,别无选择

  3. # 3 楼答案

    这似乎是一个编译器错误——它应该是一个错误,而不是一个警告

    编译方法调用表达式Enum.valueOf(enumClass...)时,首先,捕获转换应用于参数类型

    <W extends Enum> // a new type parameter 
    Class<W> enumClass; // the type of the argument after capture conversion
    

    然后,对Enum.<T>valueOf(enumClass...)进行类型推断,结果是T=W

    然后,检查替换后T的结合,即W是否为Enum<W>的亚型

    (该过程与15.12.2.2和15.12.2.3相同;15.12.2.7肯定会产生T=W)

    在这里,检查应该失败。编译器只知道WEnum的子类型,它无法推断WEnum<W>的子类型。(好吧,我们知道这是真的,除了W=Enum;但是这种知识不存在于子类型规则中,所以编译器不使用它——我们可以通过使用MyEnum层次结构来验证这一点,编译器的行为将是相同的。)

    那么,为什么编译器只需一个警告就可以通过绑定检查呢?还有一条规则允许在带有未检查警告的情况下从Raw分配到Raw<X>。为什么允许这样做是另一个问题(不应该这样),但编译器确实感觉到Raw可分配给Raw<X>。显然,这个规则被错误地混入了上面的子类型检查步骤中,编译器认为既然WEnum,它不知何故也是一个Enum<W>,编译器通过子类型检查时只发出警告,这违反了规范

    如果这种方法调用不应该编译,那么正确的方法是什么?我看不到任何形式——只要参数enumClass的类型不是Class<X extends Enum<X>>的递归形式,那么再多的转换/转换都无法将其转换为该形式,因此无法匹配Enum.valueOf方法的签名。也许javac的人故意违反规范只是为了让这种代码可以编译