【问题标题】:Java: specific enums and generic Enum<?> parametersJava:特定枚举和通用 Enum<?> 参数
【发布时间】:2010-02-08 10:09:01
【问题描述】:

我想将任何枚举值传递给实用程序类中的方法并获取另一个相同枚举类型的枚举值。像这样的:

public class XMLUtils {

    public static Enum<?> getEnumAttribute(Element element, String name, 
            Enum<?> defaultValue) {

        if (element.hasAttribute(name)) {
            String valueName = element.getAttribute(name);
            // search for value 
            for (Enum<?> value: defaultValue.getClass().getEnumConstants())
                if (value.toString().equalsIgnoreCase(valueName))
                    return value;
        }
        // not found, return default value
        return defaultValue;
    } 
}

方法getEnumAttribute()的使用:

// simple enum
public enum EUploadMethod {
    INSERT, UPDATE, DELETE
}

// read enum value from XML config file
EUploadMethod method = XMLUtils.getEnumAttribute(element, "method",
        EUploadMethod.INSERT);

此代码功能齐全,Eclipse 编译并运行它时不会出现警告或错误,它的工作原理就像一个魅力。

但是当我从命令行通过 Maven2 清理和编译项目时,它失败并出现错误,在getEnumAttribute 被调用的行:

$ mvn clean compile
....
[ERROR] /home/.... DataUploader.java:[173,53] inconvertible types
found   : java.lang.Enum<capture#414 of ?>
required: .....DataUploader.EUploadMethod

我在 Eclipse 和 Maven 中使用 Sun JDK 1.6:

$ mvn -version
Apache Maven 2.2.1 (r801777; 2009-08-06 21:16:01+0200)
Java version: 1.6.0_14
Java home: /usr/lib/jvm/java-6-sun-1.6.0.14/jre
Default locale: en_US, platform encoding: UTF-8
OS name: "linux" version: "2.6.27-17-generic" arch: "i386" Family: "unix"

问题:

  1. 为什么这段代码是可编译的并且在 Eclipse 中可以运行,并且编译 在 Maven 中失败,据我所知使用相同的 javac 编译器?

  2. 将特定枚举传递给通用 Enum&lt;?&gt; 参数有什么问题?

谢谢,

马丁·沙纳

【问题讨论】:

  • 我删除了 maven-2 标签,因为这不是与 maven 相关的问题,而是纯粹的 eclipse/javac 编译器问题。
  • Eclipse 有自己的编译器,独立于 JDK。这就是它不需要安装 JDK 的原因(您只需要 JRE。)

标签: java eclipse generics compiler-construction javac


【解决方案1】:
  1. Eclipse 编译器和 javac 有一些区别,尤其是在泛型方面。人们相信日食是正确的,但这并不重要:)

  2. 试试

    public static <T extends Enum<T>> Enum<T> getEnumAttribute(Element element, String name, 
        Enum<T> defaultValue) {
       ...
    }
    

【讨论】:

  • 谢谢你,你是绝对正确的,伙计!使用您的替代方法签名是我可以在 Eclipse 和 Maven 中编译的源代码。我对两个编译器之间的差异有点困惑......无论如何,再次感谢您!
  • 约束&lt;T extends Enum&lt;T&gt;&gt; 是正确的,但您可以将T(实际的枚举类型)设为返回类型,而不是Enum&lt;T&gt;,后者是T 的抽象超类。
【解决方案2】:

我不知道您使用的是什么版本的 Eclipse,但我认为这里是错误的。我的版本报告的错误与您在 Maven 中看到的相同,这似乎是真正的错误。

问题是getEnumAttribute() 的签名中有两个通配符("?"),但没有约束(也不可能创建一个)强制它们相同。因此,客户端可以传入一个类型的枚举作为默认值,并返回一个不同类型的枚举。

您可以通过将两个通配符替换为命名类型参数来消除调用代码中的错误:

class XMLUtils {

    @SuppressWarnings("unchecked")
    public static <E extends Enum<E>> E getEnumAttribute(Element element, String name, 
            E defaultValue) {

        if (element.hasAttribute(name)) {
            String valueName = element.getAttribute(name);
            // search for value 
            for (Enum<?> value: defaultValue.getClass().getEnumConstants())
                if (value.toString().equalsIgnoreCase(valueName))
                    return (E) value;
        }
        // not found, return default value
        return defaultValue;
    } 
}

但我认为不可能消除未经检查的强制转换,因为Enum&lt;E&gt;.getClass() 返回Class&lt;Enum&lt;?&gt;&gt;,因此编译器无法判断enumConstants 数组中包含什么类型的枚举。

【讨论】:

  • 感谢您的理论分析,尤其是对两种不同枚举类型(一种用于defaultValue,一种用于结果)的“不需要”容忍度很重要,但在我的情况下,它可能不会导致很多错误。为了完整性:我使用的是 Eclipse 3.5.1。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多