11

我想用两个“值”相同的常量定义一个枚举类型。我将这两个常量称为重复项。考虑以下示例:我想定义一个浏览器类型列表,并且我希望同时拥有文字“IE”和“InternetExplorer”,如下所示:

enum Browser {
    CHROME("chrome"),
    FIREFOX("firefox"),
    IE("ie"),
    INTERNETEXPLORER("ie");

    String type;
    Browser(String type) {
        this.type = type;
    }
}

但是,这样,以下代码将失败,

Browser a = Browser.IE;
Browser b = Browser.INTERNETEXPLORER;
Assert.assertTrue(a==b);

我能想到的唯一解决方法是添加一个返回浏览器实例内部值的类型的value()方法。Browser平等测试代码将是

Assert.assertTrue(a.value()==b.value())

这不好。那么有人有更好的主意吗?

为什么Java不允许覆盖类equals()Enum<T>类的方法?

编辑

好的,感谢您的回答和评论。我同意我最初的想法是违背枚举的目的。我认为以下更改可以满足我的需要。

public enum Browser {
   CHROME,
   FIREFOX,
   IE;

   public static Browser valueOfType(String type) {
       if (b == null) {
            throw new IllegalArgumentException("No browser of type " + type);
       switch (type.toLowerCase()) {   
          case "chrome":
               return Browser.CHROME;
          case "firefox":
               return Browser.FIREFOX;
          case "ie":
          case "internetexplorer":
          case "msie":
               return Browser.IE;
          default:
               throw new IllegalArgumentException("No browser of type " + type);
       }
   }
}
4

7 回答 7

10

在这种情况下,分层枚举技巧可能是您想要的。尽管它不能解决比较问题,但它为您的问题提供了一个非常好的替代方案。

http://java.dzone.com/articles/enum-tricks-hierarchical-data

我直接引用了上面网站的代码,并稍作简化:

public enum OsType {
    OS(null),
        Windows(OS),
            WindowsNT(Windows),
                WindowsNTWorkstation(WindowsNT),
                WindowsNTServer(WindowsNT),
            WindowsXp(Windows),
            WindowsVista(Windows),
            Windows7(Windows),
        Unix(OS),
            Linux(Unix),
    ;
    private OsType parent = null;

    private OsType(OsType parent) {
        this.parent = parent;
    }
}
于 2012-09-20T12:12:49.707 回答
9

一种简单的方法是将实例变量放在枚举类中。

enum Browser {
    CHROME,
    FIREFOX,
    INTERNETEXPLORER;
    public static final Browser IE=INTERNETEXPLORER;
}

然后,IE 应该只是作为 的别名INTERNETEXPLORER,您可以互换使用它们。

编辑:感谢 big_m 建议制作 IE final

EDIT2:这个技巧应该适用于大多数代码,但如果你使用switch/case. 这是一个例子:

Browser b;
switch(b){
    case Browser.CHROME:
        //code for chrome
        break;
    case Browser.IE: // <---- SYNTAX ERROR, use Browser.INTERNETEXPLORER in this case
        //code for internet explorer
        break;
}
于 2016-05-07T18:48:14.797 回答
8

每个枚举相互扩展Enum定义equals()为的类final。这样做是因为 enum 不是常规类。JVM 保证每个枚举元素都是唯一的,即在一个JVM 中每个元素只存在一个实例。

例如,在switch语句等中使用枚举时需要这样做。

你想要做的是违背这个概念:你希望同一个枚举有 2 个相等的成员。

但是我可以为您提供其他解决方案:只定义一个IE成员。将成员定义String[]到可以通过任何别名找到适当成员的枚举和方法中:

public enum Browser {


    CHROME("Chrome"),
    FIREFOX("FireFox"),
    IE("IE", "MSIE", "Microsoft Internet Exporer"),
    ;

    private String[] aliases;

    private static Map<String, Browser> browsers = new HashMap<>();
    static {
        for (Browser b : Browser.values()) {
            for (String alias : b.aliases) {
                browsers.put(alias, b);
            }
        }
    }

    private Browser(String ... aliases) {
        this.aliases = aliases;
    }

    public static Browser valueOfByAlias(String alias) {
        Browser b = browsers.get(alias);
        if (b == null) {
            throw new IllegalArgumentException(
                    "No enum alias " + Browser.class.getCanonicalName() + "." + alias);
        }
        return b;
    }
}
于 2012-09-20T12:03:39.650 回答
2

您不能覆盖equals()枚举的方法,但即使您可以,==操作员也不会执行该equals()方法:您的示例a == b无法true实现。

我能想到的最接近的是实用程序(静态)方法:

enum Browser {
    CHROME("chrome"),
    FIREFOX("firefox"),
    IE("ie"),
    INTERNETEXPLORER("ie");

    private final String type;
    Browser(String type) {
        this.type = type;
    }

    public String getType() {
        return type;
    }

    public static boolean equals(Browser b1, Browser b2) {
        return b1.type.equals(b2.type);
    }
}

另请注意,我会制作type private final. 事实上,你可以这样做:

IE.type = "netscape"; // would be allowed
于 2012-09-20T11:53:23.600 回答
0

你真正应该做的是规范化输入到枚举的转换,即如果你的输入(来自用户/数据存储)是 IE/INTERNETEXPLORER,它应该被解析为 Browser.IE。这将删除代码中的大量冗余检查,以查看枚举是 IE 还是 INTERNETEXPLORER。

于 2012-09-20T11:53:43.170 回答
0

写在Enum课堂上

但是扩展这个类不会使一个类成为枚举类型,因为编译器需要为它生成特殊信息。

为了支持基于引用equals方法的相等性是最终的。

您可以使用EnumSet创建EnumSet相关枚举,然后您可以使用contains方法。

public static EnumSet<Browser> MSE = EnumSet.of(Browser.IE,
    Browser.INTERNETEXPLORER);

因此,您的代码将如下所示。

public enum Browser {
CHROME("chrome"), FIREFOX("firefox"), IE("ie"), INTERNETEXPLORER("ie");

String type;

Browser(String type) {
    this.type = type;
}

public static EnumSet<Browser> MSE = EnumSet.of(Browser.IE,
        Browser.INTERNETEXPLORER);

public static void main(String[] args) {
    System.out.println(MSE.contains(Browser.IE));//true
    System.out.println(MSE.contains(Browser.INTERNETEXPLORER));//true
}
}
于 2012-09-20T12:24:19.803 回答
-2

我会删除字符串值和重复的 IE 实例,它没有用......

enum Browser {
    CHROME,
    FIREFOX,
    IE

如果您必须使用小写表示,只需在需要时从枚举名称转换。

于 2012-09-20T11:47:35.240 回答