如何在Java中定义重复的枚举常量?

如何在Java中定义重复的枚举常量?,java,enums,Java,Enums,我想用两个“值”相同的常量定义一个枚举类型。我把这两个常数称为重复的。考虑下面的例子:我想定义一个浏览器类型列表,并且我想要既有字面的“IE”又有“Internet Explorer”,如下: enum Browser { CHROME("chrome"), FIREFOX("firefox"), IE("ie"), INTERNETEXPLORER("ie"); String type; Browser(String type) {

我想用两个“值”相同的常量定义一个枚举类型。我把这两个常数称为重复的。考虑下面的例子:我想定义一个浏览器类型列表,并且我想要既有字面的“IE”又有“Internet Explorer”,如下:

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);
我能想到的唯一解决方法是添加
Browser
类型的
value()
方法,该方法返回浏览器实例的内部值。平等性测试代码是

Assert.assertTrue(a.value()==b.value())
这不好。有人有更好的主意吗

为什么Java不允许重写
Enum
类的
equals()
之类的方法

编辑

好的,谢谢你的回答和评论。我同意我最初的想法与enum的目的背道而驰。我认为下面的变化可以满足我的需要

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

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

enum Browser {
    CHROME,
    FIREFOX,
    IE

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

不能覆盖枚举的
equals()
方法,但即使可以,
=
运算符也不会执行
equals()
method:对于您的示例,无法使
a==b
be
true

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

还请注意,我将使用
类型
私有最终版
。实际上,您可以这样做:

IE.type = "netscape"; // would be allowed

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

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

例如,在
switch
语句等中使用枚举时,这是必需的

您试图做的是违背这个概念:您希望同一个枚举有两个相等的成员

不过,我可以为您提供其他解决方案:仅定义一个
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;
    }
}
公共枚举浏览器{
铬(“铬”),
FIREFOX(“FIREFOX”),
IE(“IE”、“MSIE”、“微软互联网博览会”),
;
私有字符串[]别名;
私有静态映射浏览器=new HashMap();
静止的{
对于(浏览器b:Browser.values()){
用于(字符串别名:b.别名){
浏览器.put(别名,b);
}
}
}
专用浏览器(字符串…别名){
this.alias=别名;
}
公共静态浏览器值ByAlias(字符串别名){
Browser b=browsers.get(别名);
如果(b==null){
抛出新的IllegalArgumentException(
“无枚举别名”+Browser.class.getCanonicalName()+”+别名);
}
返回b;
}
}

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

我直接引用上述网站的代码,略为简化:

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

Enum
Class中所述

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

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

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

public static EnumSet<Browser> MSE = EnumSet.of(Browser.IE,
    Browser.INTERNETEXPLORER);
public static EnumSet MSE=EnumSet.of(Browser.IE,
浏览器(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
}
}
公共枚举浏览器{
CHROME(“CHROME”)、FIREFOX(“FIREFOX”)、IE(“IE”)、INTERNETEXPLORER(“IE”);
字符串类型;
浏览器(字符串类型){
this.type=type;
}
public static EnumSet MSE=EnumSet.of(Browser.IE,
浏览器(INTERNETEXPLORER);
公共静态void main(字符串[]args){
System.out.println(MSE.contains(Browser.IE));//true
System.out.println(MSE.contains(Browser.INTERNETEXPLORER));//true
}
}

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

enum Browser {
    CHROME,
    FIREFOX,
    INTERNETEXPLORER;
    public static final Browser IE=INTERNETEXPLORER;
}
然后,IE应该只是充当
INTERNETEXPLORER
的别名,您可以互换使用它们

编辑:感谢big_m建议将IE
定稿

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;
}
b浏览器;
开关(b){
case Browser.CHROME:
//chrome代码
打破

case Browser.IE://我不明白为什么您需要两个枚举常量
IE
internetexplorer
,如果它们是相同的。您能解释一下为什么需要它们吗?枚举的目的是创建一组受控词汇表,用于对同一概念进行分类或分组。您所做的只是违背了它的目的ose。@assylias,我需要它,因为在不同的地方,我可能想使用指向同一事物的不同标识符。也许另一个例子更有意义,有时我想使用零,有时我想使用NULL,但我希望它们的含义相同。@MingXue在我看来,这是对枚举的错误使用:零和NULL代表输入相同的内容时,应该只有一个常量,否则应该没有,应该有两个常量,而不是
=
。换句话说,重新考虑您的设计。为什么不使用uni创建
enum
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;
}