【问题标题】:Enum.valueOf throws a warning for unknown type of class that extends Enum?Enum.valueOf 对扩展 Enum 的未知类型的类抛出警告?
【发布时间】:2011-08-12 15:26:14
【问题描述】:

给这个:

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

[unchecked] 未经检查的方法调用: java.lang.Enum 中的 valueOf(java.lang.Class,java.lang.String) 是 应用于(java.lang.Class,java.lang.String)

我不想使用泛型,因为这是一个重大变化。我不想压抑。我不明白为什么会发生此警告。我想这是因为无法扩展 Enum 类型。我明白了。但我不明白为什么通配符类会抛出这个奇怪的错误。有没有办法在不使用@SupressWarning 或使用泛型的情况下解决这个问题?

编辑:为了澄清,以下使用泛型的代码使警告消失。

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

&lt;T&gt; 的用法就是我使用泛型的意思。我不能这样做,因为这将是一个巨大的级联变化。

【问题讨论】:

  • 你在初始化enumClass吗?另外,我不明白你将如何使用泛型来解决这个问题;你有什么想法? (顺便说一句,您已经在enumClass 的声明中使用了泛型;为什么使用泛型会是“重大变化”?)
  • 所以最终答案,如果不使用@SupressWarning,这是不可能的。

标签: java enums


【解决方案1】:

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;
}

但是,如果您不使用泛型,那么您使用的是原始类型,因此编译器会发出警告 - 除了禁止它们之外别无选择。

【讨论】:

  • 那么 Enum.valueOf 应该如何解决“foo”?
  • 它当然是一个占位符。我会用变量替换它
  • 但我说我不能使用泛型,因为我无法控制。那么这对我有什么帮助呢?
  • @Amir Raminfar 但您在代码中使用了泛型 - &lt;? etends Enum&gt;。如果您使用原始类型 - 您会收到警告。没办法(查看我的最后一段)
  • 是的,我花了很多时间试图在不产生警告的情况下解决这个问题。使用泛型类型是正确的方法,但我不能,因为我正在修改别人的代码。我认为抑制警告可能是唯一的解决方案。这是有道理的,因为枚举无法扩展,所以 javac 抱怨不知道该类型是什么。我希望有更好的方法。
【解决方案2】:

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

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

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

然后,对Enum.&lt;T&gt;valueOf(enumClass...)进行类型推断,结果为T=W

然后,检查替换后T的边界,即W是否是Enum&lt;W&gt;的子类型。

(这个过程对于 15.12.2.2 和 15.12.2.3 是一样的;而 15.12.2.7 肯定会产生 T=W)

在这里,检查应该失败。所有编译器都知道WEnum 的子类型,它不能推断WEnum&lt;W&gt; 的子类型。 (好吧,我们知道这是真的,除了W=Enum;但是这个知识在子类型规则中不存在,所以编译器不使用它——我们可以通过使用MyEnum层次结构来验证这个例子,编译器会表现一样。)

那么为什么编译器会通过绑定检查并只发出警告?还有另一条规则允许从 Raw 分配到 Raw&lt;X&gt; 并带有未经检查的警告。为什么允许这样做是另一个问题(不应该),但编译器确实认为Raw 可以分配给Raw&lt;X&gt;。显然这条规则被错误地混入了上面的子类型检查步骤,编译器认为由于WEnum,它在某种程度上也是一个Enum&lt;W&gt;,编译器通过子类型检查只是一个警告,违反规范.

如果这样的方法调用不应该编译,那么正确的方法是什么?我什么都看不到 - 只要参数enumClass 的类型还不是Class&lt;X extends Enum&lt;X&gt;&gt; 的递归形式,就没有多少铸件/转换可以使它变成那种形式,因此没有办法匹配Enum.valueOf 方法的签名。也许javac家伙故意违反规范只是为了让这种代码编译!

【讨论】:

    【解决方案3】:

    如果您考虑一下 valueOf 内部必须发生的事情,您会意识到您的代码不可能像编写的那样工作。 Enum.valueOf 需要一个实际枚举类的实例作为参数;然后它会简单地遍历 values() 以寻找匹配项。

    由于type erasure,泛型无法在您的代码中工作。没有实际类型被传递到 Enum.valueOf

    【讨论】:

    • 混淆了你在说什么,因为代码有效。我只是不想收到警告。
    • 如果您的代码正常工作,您就没有向我们展示您的代码。特别是,enumClass 在您发布的代码中将是 null,这绝对行不通。
    • 我更新了我的代码。 enumClass 正在传递。我认为这很清楚。对不起。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-01
    • 2011-03-08
    • 2021-01-09
    • 1970-01-01
    • 2021-07-11
    • 2023-03-19
    • 2020-02-02
    相关资源
    最近更新 更多