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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12511931/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 09:11:05  来源:igfitidea点击:

How can I define duplicate enumeration constants in Java?

javaenums

提问by Ming Xue

I want to define an enum type with two constants whose "value" is the same. I call these two constants as duplicates. Consider the following example: I want to define a list of browser types, and I want to have both a literal "IE" and "InternetExplorer", as below:

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

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

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

However, with this, the following code will fail,

但是,有了这个,以下代码将失败,

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

The only workaround I can think of is that to add a value()method of the Browsertype that returns the internal value of the browser instance. And the equality test code would be

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

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

This is not nice. So does anyone have a better idea?

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

Why does Java not allow to override methods like equals()of Enum<T>class?

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

EDIT:

编辑

OK, thanks for the answers and comments. I agree that my original thought was against the purpose of enum. I think the following changes can meet my need.

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

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

采纳答案by AlexR

Each enum mutually extends class Enumthat defines equals()as final. This is done because enum is not a regular class. JVM guarantees that each enum element is unique, i.e. exists only one instance of each element within one JVM.

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

This is required for example for using enums in switchstatement etc.

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

What you are trying to do is to go against this concept: you want to have 2 equal members of the same enum.

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

However I can offer you other solution: define only one IEmember. Define String[]member into the enum and method that can find appropriate member by any alias:

但是我可以为您提供其他解决方案:仅定义一个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;
    }
}

回答by XeroOl

One simple way to do this is to put instance variables inside your enum class.

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

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

Then, IE should just act as an alias to INTERNETEXPLORER, and you can use them interchangeably.

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

EDIT: Thanks to big_m for suggesting to make IE final!

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

EDIT2: This trick should work in most code, but there's an exception if you are using switch/case. Here's an example:

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

回答by gigadot

Hierarchical enumeration trick is probably what you want in this case. Although it doesn't solve the comparison problem, it provides a very nice alternative to you problem.

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

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

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

I quote the codes from the site above directly with slight simplification:

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

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

回答by Bohemian

You can't override the equals()method for an enum, but even if you could the ==operator does not execute the equals()method: There is no way to make a == bbe truefor your example.

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

The closest I can think of is a utility (static) method:

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

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

Also note that I would make typeprivate final. As it is, you can do this:

还要注意,我会让typeprivate final. 事实上,你可以这样做:

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

回答by Vikdor

What you should really do is normalize the conversion of input to enum, i.e. if your input (from user/data store) is IE/INTERNETEXPLORER, it should be resolved to Browser.IE. That would remove a lot of redundant checks in the code to see if the enum is IE or INTERNETEXPLORER.

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

回答by Amit Deshpande

As Written In EnumClass

Enum课堂上写的

but extending this class does not make a class an enumeration type, since the compiler needs to generate special information for it.

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

In order to support equality based on reference equalsmethod is final.

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

You can use EnumSetto create EnumSetof Related enums and then you can use containsmethod.

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

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

So your code will look something like below.

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

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

回答by NimChimpsky

I would remove the string value and the duplicate IE instance, its of no use ...

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

enum Browser {
    CHROME,
    FIREFOX,
    IE

If you must have lower case representation just convert from enum name when you need it.

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