如何在Java中定义重复的枚举常量?
我想用两个“值”相同的常量定义一个枚举类型。我把这两个常数称为重复的。考虑下面的例子:我想定义一个浏览器类型列表,并且我想要既有字面的“IE”又有“Internet Explorer”,如下:如何在Java中定义重复的枚举常量?,java,enums,Java,Enums,我想用两个“值”相同的常量定义一个枚举类型。我把这两个常数称为重复的。考虑下面的例子:我想定义一个浏览器类型列表,并且我想要既有字面的“IE”又有“Internet Explorer”,如下: enum Browser { CHROME("chrome"), FIREFOX("firefox"), IE("ie"), INTERNETEXPLORER("ie"); String type; Browser(String type) {
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
betrue
我能想到的最接近实用程序(静态)方法:
还请注意,我将使用类型
私有最终版
。实际上,您可以这样做:
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;
}