我对C#非常熟悉,但开始在Java中工作更多。我希望得知Java中的枚举基本上与C#中的枚举相同,但显然情况并非如此。最初,我很高兴得知Java枚举可以包含多个数据,这看起来非常有利(http://docs.oracle.com/javase/tutorial/java/javaOO/enum.html)。然而,从那时起我发现C#中缺少很多功能,例如能够轻松地为枚举元素分配特定值,从而能够在没有相当大努力的情况下将整数转换为枚举(即Convert integer value to matching Java Enum)。
所以我的问题是:对于带有一堆公共静态最终字段的类,Java枚举是否有任何好处?或者它只提供更紧凑的语法?
编辑:让我更清楚一点。与具有相同类型的相同的公共静态最终字段的类相比,Java枚举有什么好处?例如,在第一个链接的行星示例中,枚举对具有这些公共常量的类有什么好处:public static final Planet MERCURY = new Planet(3.303e+23, 2.4397e6);
public static final Planet VENUS = new Planet(4.869e+24, 6.0518e6);
public static final Planet EARTH = new Planet(5.976e+24, 6.37814e6);
public static final Planet MARS = new Planet(6.421e+23, 3.3972e6);
public static final Planet JUPITER = new Planet(1.9e+27, 7.1492e7);
public static final Planet SATURN = new Planet(5.688e+26, 6.0268e7);
public static final Planet URANUS = new Planet(8.686e+25, 2.5559e7);
public static final Planet NEPTUNE = new Planet(1.024e+26, 2.4746e7);
据我所知,卡萨布兰卡的答案是唯一能满足这一要求的答案。
答案 0 :(得分:91)
switch
语句case
语句中使用值。ordinal().
EnumSet
和EnumMap
个类。 答案 1 :(得分:73)
没有人提到在switch
陈述中使用它们的能力;我也会把它扔进去。
这允许以干净的方式使用任意复杂的枚举,而不使用instanceof
,可能会混淆if
序列或非字符串/ int切换值。规范示例是状态机。
答案 2 :(得分:70)
从技术上讲,人们确实可以将枚举视为一个带有一堆类型常量的类,这实际上是如何在内部实现枚举常量。但是,使用enum
会为您提供有用的方法(Enum javadoc),否则您必须自己实施这些方法,例如Enum.valueOf
。
答案 3 :(得分:42)
混淆较少。以Font
为例。它有一个构造函数,它带有你想要的Font
的名称,它的大小和样式(new Font(String, int, int)
)。直到今天,我还记不起风格或尺寸是否先行。如果Font
使用enum
表示其所有不同的样式(PLAIN
,BOLD
,ITALIC
,BOLD_ITALIC
),则其构造函数会显示像Font(String, Style, int)
一样,防止任何混淆。不幸的是,enum
类在创建Font
类时并不存在,并且由于Java必须保持反向兼容性,我们总是会受到这种模糊性的困扰。
当然,这只是使用enum
而不是public static final
常量的论据。枚举也适用于singletons并实现默认行为,同时允许以后的自定义(I.E. strategy pattern)。后者的一个示例是java.nio.file
的{{3}}和OpenOption
:如果开发人员想要创建自己的非标准OpenOption
,他就可以。
答案 4 :(得分:42)
主要优点是类型安全。使用一组常量,可以使用相同内在类型的任何值,从而引入错误。使用枚举时,只能使用适用的值。
例如
public static final int SIZE_SMALL = 1;
public static final int SIZE_MEDIUM = 2;
public static final int SIZE_LARGE = 3;
public void setSize(int newSize) { ... }
obj.setSize(15); // Compiles but likely to fail later
VS
public enum Size { SMALL, MEDIUM, LARGE };
public void setSize(Size s) { ... }
obj.setSize( ? ); // Can't even express the above example with an enum
答案 5 :(得分:24)
这里有很多好的答案,但没有一个提到有专门针对枚举的Collection API类/接口的高度优化的实现:
这些枚举特定类只接受Enum
个实例(EnumMap
仅接受Enum
仅作为键),并且只要有可能,它们会在其实现中恢复为紧凑表示和位操作
这是什么意思?
如果我们的Enum
类型不超过64个元素(大多数现实Enum
示例将符合此条件),则实现将元素存储在单个long
值中,有问题的每个Enum
实例将与此64位长long
的位相关联。将元素添加到EnumSet
只是将正确的位设置为1,删除它只是将该位设置为0.测试元素是否在Set
中只是一个位掩码测试!现在你必须为此爱Enum
!
答案 6 :(得分:11)
正如您已经注意到的,枚举的第一个好处是语法简洁。但是枚举的主要目的是提供一组众所周知的常量,默认情况下,这些常量形成一个范围,并通过类型和方式帮助执行更全面的代码分析。价值安全检查。
枚举的这些属性可以帮助程序员和编译器。例如,假设您看到一个接受整数的函数。整数意味着什么?你能传递什么样的价值观?你真的不知道。但是如果你看到一个接受枚举的函数,你就会非常清楚所有可以传入的值。
对于编译器,枚举有助于确定一系列值,除非您为枚举成员指定特殊值,否则它们的范围从0到更高。这有助于通过类型安全检查等自动跟踪代码中的错误。例如,编译器可能会警告您在switch语句中没有处理所有可能的枚举值(即,当您没有default
大小写并且只处理N个枚举值中的一个时)。当你将任意整数转换为枚举时,它也会发出警告,因为枚举的值范围小于整数,而这反过来可能会触发函数中不会真正接受整数的错误。此外,当值从0开始时,为开关生成跳转表变得更容易。
这不仅适用于Java,也适用于其他具有严格类型检查的语言。 C,C ++,D,C#就是很好的例子。
答案 7 :(得分:10)
示例:
public class CurrencyDenom {
public static final int PENNY = 1;
public static final int NICKLE = 5;
public static final int DIME = 10;
public static final int QUARTER = 25;}
java常量的限制
1)无类型安全:首先,它不是类型安全的;你可以将任何有效的int值赋给int,例如99虽然没有硬币来代表这个价值。
2)无意义打印:任何这些常量的打印值将打印其数值而不是有意义的硬币名称,例如当您打印NICKLE时,它将打印" 5"而不是" NICKLE"
3)无名称空间:要访问currencyDenom常量,我们需要为类名添加前缀,例如CurrencyDenom.PENNY而不仅仅是使用PENNY,虽然这也可以通过在JDK 1.5中使用静态导入来实现
枚举的优点
1)Java中的枚举是类型安全的,并且有自己的名称空间。这意味着你的枚举将有一个类型,例如"货币"在下面的示例中,您不能分配除枚举常量中指定的任何值。
public enum Currency {PENNY, NICKLE, DIME, QUARTER};
Currency coin = Currency.PENNY;
coin = 1; //compilation error
2)Java中的Enum是类或接口的引用类型,您可以在java Enum中定义构造函数,方法和变量,这使得它在C和C ++中比Enum更强大,如下面的Java Enum类型示例所示。
3)您可以在创建时指定枚举常量的值,如下例所示: public enum Currency {PENNY(1),NICKLE(5),DIME(10),QUARTER(25)}; 但为了实现这一点,你需要定义一个成员变量和一个构造函数,因为PENNY(1)实际上是在调用一个接受int值的构造函数,见下面的例子。
public enum Currency {
PENNY(1), NICKLE(5), DIME(10), QUARTER(25);
private int value;
private Currency(int value) {
this.value = value;
}
};
参考:https://javarevisited.blogspot.com/2011/08/enum-in-java-example-tutorial.html
答案 8 :(得分:4)
枚举好处:
“例如能够轻松地将枚举元素分配给某个值”
enum EnumX{
VAL_1(1),
VAL_200(200);
public final int certainValue;
private X(int certainValue){this.certainValue = certainValue;}
}
“因此能够在没有相当大努力的情况下将整数转换为枚举” 添加一个将int转换为枚举的方法。只需添加包含映射的静态HashMap。
如果你真的想将ord = VAL_200.ordinal()转换回val_200,只需使用:EnumX.values()[ord]
答案 9 :(得分:4)
枚举是隐含最终的,具有私有构造函数,其所有值都属于同一类型或子类型,您可以使用values()
获取其所有值,获取其name()
或{ {1}}值或您可以按编号或名称查找枚举。
你也可以定义子类(即使在概念上是最终的,你也不能做任何其他方式)
ordinal()
答案 10 :(得分:3)
另一个重要区别是java编译器将基本类型和 String 的static final
字段视为文字。这意味着这些常量变为内联。它与C/C++
#define
预处理器类似。见this SO question。枚举不是这种情况。
答案 11 :(得分:2)
使用枚举时,您将获得有效值的编译时检查。看this question.
答案 12 :(得分:2)
最大的优点是enum Singletons易于编写和线程安全:
public enum EasySingleton{
INSTANCE;
}
和
/**
* Singleton pattern example with Double checked Locking
*/
public class DoubleCheckedLockingSingleton{
private volatile DoubleCheckedLockingSingleton INSTANCE;
private DoubleCheckedLockingSingleton(){}
public DoubleCheckedLockingSingleton getInstance(){
if(INSTANCE == null){
synchronized(DoubleCheckedLockingSingleton.class){
//double checking Singleton instance
if(INSTANCE == null){
INSTANCE = new DoubleCheckedLockingSingleton();
}
}
}
return INSTANCE;
}
}
两者都相似,它通过实现
自行处理序列化//readResolve to prevent another instance of Singleton
private Object readResolve(){
return INSTANCE;
}
答案 13 :(得分:0)
从 Java 16 开始,枚举可以在本地(在方法内)定义。除了能够将枚举定义为嵌套或单独的类之外,此范围还可以。
这个新的本地定义范围与新的记录功能一起出现。有关详细信息,请参阅 JEP 395: Records。枚举、接口和记录都可以在 Java 16+ 中本地定义。
相比之下,public static final
字段始终具有全局范围。
答案 14 :(得分:0)
主要原因:枚举可帮助您编写结构良好的代码,其中参数的语义含义在编译时清晰明了且具有强类型-出于其他答案的所有原因。
十分严格的:在Java中,开箱即用的是Enum成员数组。通常这很好,因为它可以帮助评估安全性和测试价值,但是在某些情况下,这可能是一个缺点,例如,如果您要从库中扩展现有的基本代码。相反,如果在具有静态字段的类中使用相同的数据,则可以在运行时轻松地添加该类的新实例(您可能还需要编写代码以将其添加到该类的任何Iterable中)。但是Enums的这种行为可以更改:使用反射,您可以在运行时添加新成员或替换现有成员,尽管这可能仅应在没有其他选择的特殊情况下才能完成:例如,这是一个棘手的解决方案,可能会产生意外问题,在Can I add and remove elements of enumeration at runtime in Java上查看我的答案。
答案 15 :(得分:0)
此处列出的枚举有很多优点,我现在正在按照问题的要求创建此类枚举。 但是我有一个5-6个字段的枚举。
Example: <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/view1/"/>
<property name="prefix" value="/WEB-INF/view2/"/>
<property name="suffix" value=".jsp"/>
</bean>
在这种情况下,当枚举中有多个字段时,很难理解哪个值属于哪个字段,因为您需要查看构造函数和注意事项。
具有enum Planet{
EARTH(1000000, 312312321,31232131, "some text", "", 12),
....
other planets
....
常量的类,并使用static final
模式创建此类对象,使其更具可读性。但是,如果需要,您将失去使用枚举的所有其他优点。
这种类的一个缺点是,您需要手动将Builder
对象添加到Planet
的{{1}}
与此类相比,我仍然更喜欢枚举,因为list/set
派上了用场,并且您永远都不知道将来是否需要在Planets.
或values()
或switch
中使用它们:)
答案 16 :(得分:0)
我认为enum
不能是final
,因为在引擎盖编译器下为每个enum
条目生成子类。
更多信息来自source