What's the advantage of a Java enum versus a class with public static final fields?
我对C语言非常熟悉,但开始更多的使用Java语言。我原以为Java中的枚举基本上等同于C语言,但是显然不是这样。最初,我很兴奋地知道Java枚举可以包含多条数据,这些数据看起来非常有利(http://DOCS.Oracle .COM/JavaSe/Trave/Java/javao/EnUn.html)。然而,从那时起,我发现在C语言中缺少许多琐碎的特征,例如能够容易地将枚举元素赋给某个值,并因此将整数转换为枚举而无需付出相当多的努力(即将整数值转换为匹配的JavaEnUM)。
所以我的问题是:在一组公共静态最终字段上,Java枚举有什么好处吗?或者它只是提供了更紧凑的语法?
编辑:让我更清楚一点。Java枚举对一组具有相同类型的公共静态最终字段的类有什么好处?例如,在第一个链接的行星示例中,枚举相对于具有这些公共常量的类有什么优势:
1 2 3 4 5 6 7 8 | 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); |
据我所知,卡萨布兰卡的回答是唯一能满足这一点的。
没有人提到在
这允许以干净的方式使用任意复杂的枚举,而不使用
从技术上讲,人们确实可以将枚举视为一个具有一系列类型化常量的类,实际上,这就是枚举常量在内部实现的方式。但是,使用
不那么混乱。以
当然,这只是使用
主要优点是类型安全。使用一组常量,可以使用相同内部类型的任何值,从而引入错误。对于枚举,只能使用适用的值。
例如
1 2 3 4 5 6 7 | 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
1 2 3 4 5 | public enum Size { SMALL, MEDIUM, LARGE }; public void setSize(Size s) { ... } obj.setSize( ? ); // Can't even express the above example with an enum |
这里有许多很好的答案,但没有一个提到集合API类/接口的高度优化实现,专门针对枚举:
- 枚举集
- 枚举图
这些枚举特定的类只接受
这是什么意思?
如果我们的
正如您已经注意到的,枚举的第一个好处是语法简单。但是枚举的要点是提供一组众所周知的常量,默认情况下,这些常量构成一个范围,并通过类型和值安全检查帮助执行更全面的代码分析。
枚举的这些属性对程序员和编译器都有帮助。例如,假设您看到一个接受整数的函数。那个整数意味着什么?你能传递什么样的价值观?你现在还不知道。但是,如果您看到一个接受枚举的函数,那么您就非常清楚可以传入的所有可能值。
对于编译器,枚举有助于确定值的范围,除非为枚举成员指定特殊值,否则它们的范围为0到更大。这有助于通过类型安全检查等自动跟踪代码中的错误。例如,编译器可能会警告您,在switch语句中不处理所有可能的枚举值(即,当您没有
这不仅对Java来说是正确的,而且对于其他具有严格类型检查的语言也是如此。C、C++、D、C是很好的例子。
例子:
1 2 3 4 5 | 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)无意义的打印:这些常量中的任何一个的打印值都将打印其数值而不是有意义的硬币名称,例如,当您打印镍币时,它将打印"5"而不是"镍币"。
3)没有名称空间:要访问currencydenom常量,我们需要给类名加前缀,例如currencydenom.penny,而不是只使用penny,尽管这也可以通过在JDK 1.5中使用静态导入来实现。
枚举的优点
1)Java中的枚举是类型安全的,并且有自己的名称空间。这意味着在下面的示例中,枚举将具有例如"currency"的类型,并且除了在枚举常量中指定的值之外,您不能分配任何值。
1 | public enum Currency {PENNY, NICKLE, DIME, QUARTER}; |
coin = 1; //compilation error
2)Java中的枚举是类或接口的引用类型,您可以在JavaEnm中定义构造函数、方法和变量,这使得它在C和C++中比EnUM强大,如下一个JavaEnm类型的示例所示。
3)您可以在创建时指定枚举常量的值,如下例所示:公共枚举货币Penny(1)、Nickle(5)、Dime(10)、Quarter(25)但要实现这一点,您需要定义一个成员变量和一个构造函数,因为Penny(1)实际上正在调用一个接受int值的构造函数,请参见下面的示例。
1 2 3 4 5 6 7 8 | 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
枚举是隐含的最终的,有一个私有的构造函数,它的所有值都是相同的类型或子类型,您可以使用
您还可以定义子类(尽管概念上是最终的,但是您不能以任何其他方式进行定义)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
枚举收益:
"例如,能够轻松地为枚举元素分配某个值"
1 2 3 4 5 6 | enum EnumX{ VAL_1(1), VAL_200(200); public final int certainValue; private X(int certainValue){this.certainValue = certainValue;} } |
"因此,能够将一个整数转换为一个枚举,而无需付出相当大的努力"添加一个将int转换为枚举的方法。只需添加包含映射的静态哈希映射。
如果您真的想将ord=val_200.ordinal()转换回val_200,只需使用:enumx.values()[ord]
另一个重要区别是Java编译器将EDCOX1的26个字段的基元类型和字符串视为文字。这意味着这些常量变成了内联的。类似于
最大的优点是枚举单例易于编写和线程安全:
1 2 3 | public enum EasySingleton{ INSTANCE; } |
和
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /** * 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; } } |
两者都是相似的,它通过实现
1 2 3 4 | //readResolve to prevent another instance of Singleton private Object readResolve(){ return INSTANCE; } |
更多
当使用枚举时,您将获得有效值的编译时检查。看看这个问题。
我认为
来自来源的更多信息