Java枚举与具有公共静态最终字段的类相比有什么优势?

Cra*_*g W 134 java enums

我对C#非常熟悉,但开始在Java中工作更多.我希望得知Java中的枚举基本上与C#中的枚举相同,但显然情况并非如此.最初,我很高兴得知Java枚举可能包含多个数据,这似乎非常有利(http://docs.oracle.com/javase/tutorial/java/javaOO/enum.html).但是,从那时起我发现C#中缺少许多功能,例如能够轻松地为枚举元素分配特定值,以及因此无需花费大量精力就能将整数转换为枚举(即整数值转换为相匹配的Java枚举).

所以我的问题是:对于带有一堆公共静态最终字段的类,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);
Run Code Online (Sandbox Code Playgroud)

据我所知,卡萨布兰卡的答案是唯一能满足这一要求的人.

use*_*421 94

  1. 类型安全和价值安全.
  2. 保证单身.
  3. 能够定义和覆盖方法.
  4. 能够在没有限定条件的switch语句中使用值case.
  5. 通过内置的值序列化 ordinal().
  6. 按名称而不是按值进行序列化,这提供了一定程度的面向未来.
  7. EnumSetEnumMap课程.

  • 说了这么多,每当我把代码放入Enum时我就后悔了. (14认同)
  • 你为什么后悔呢?我从来没有...... (3认同)
  • @glglgl 因为它把特定于应用程序的代码放在一个我觉得它并不真正属于的地方,那实际上只是定义了一组值。如果让我再做一次,我会将它包含在众多 `switch` 语句之一中,而这正是使用 `Enum` 的最初动机。 (2认同)

cas*_*nca 76

从技术上讲,人们确实可以将枚举视为一个带有一堆类型常量的类,这实际上是如何在内部实现枚举常量.enum然而,使用a 为您提供了有用的方法(Enum javadoc),否则您必须自己实现,例如Enum.valueOf.

  • 还有`.values()`迭代值列表. (12认同)
  • @Craig你的直觉是对的 - 这是一个非常糟糕的答案,因为它完全错过了枚举的目的.有关部分原因,请参阅我在问题下的评论. (7认同)

Dav*_*ton 73

没有人提到在switch陈述中使用它们的能力; 我也会把它扔进去.

这允许以干净的方式使用任意复杂的枚举,而不使用instanceof可能混淆的if序列或非字符串/ int切换值.规范示例是状态机.

  • @Genaut 当“Planet”不是“enum”时如何切换“Planet”实例? (2认同)

Jim*_*son 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
Run Code Online (Sandbox Code Playgroud)

VS

public enum Size { SMALL, MEDIUM, LARGE };

public void setSize(Size s) { ... }

obj.setSize( ? ); // Can't even express the above example with an enum
Run Code Online (Sandbox Code Playgroud)

  • 类也是类型安全的...:/(假设静态字段属于容器类的类型) (3认同)
  • 您可以在第二个示例中调用`setSize(null)`,但它可能比第一个示例的错误早得多. (2认同)

Jef*_*rey 42

混淆少了.举个Font例子.它有一个构造函数,它带有Font你想要的名称,它的大小和样式(new Font(String, int, int)).直到今天,我还记不起风格或尺寸是否先行.如果Font已经使用了enum其所有不同的风格(PLAIN,BOLD,ITALIC,BOLD_ITALIC),它的构造看起来像Font(String, Style, int),防止任何混乱.不幸的是,在创建类enum时,s并不存在Font,并且由于Java必须保持反向兼容性,因此我们总是会被这种模糊性所困扰.

当然,这只是使用enum而不是public static final常量的论据.枚举也非常适合单身人士和实现默认行为,同时允许以后的自定义(IE 策略模式).后者的一个例子是java.nio.fileOpenOptionStandardOpenOption:如果开发者想创造自己的不规范OpenOption,他可能.


icz*_*cza 25

这里有很多好的答案,但都没有提到专门针对枚举的Collection API类/接口的高度优化实现:

这些枚举特定类只接受Enum实例(EnumMap唯一的接受Enum只作为键),并且只要有可能,它们在其实现中恢复为紧凑表示和位操作.

这是什么意思?

如果我们的Enum类型不再有64个元素(大多数现实Enum例子都符合这个要求),那么实现将元素存储在一个long值中,每个Enum有问题的实例将与这个64位长的一些相关联long.向a添加元素EnumSet只是将正确的位设置为1,删除它只是将该位设置为0.测试元素Set是否只是一个位掩码测试!现在你必须Enum为此而爱!

  • 可能值得一提的是,`EnumSet` 也对包含超过 64 个常量的类型进行了相同的优化。它只需要使用一个 `long[]` 数组而不是单个 `long`。虽然将 `add`、`remove` 和 `contains` 操作减少到单个位操作是很棒的,但真正有趣的开始是像 `addAll`、`removeAll` 和 `retainAll` 这样的操作,它们不是一点一点的,而是一次处理 64 个元素(换句话说,通常是所有元素)。 (2认同)

小智 12

例:

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;}
Run Code Online (Sandbox Code Playgroud)

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};
Run Code Online (Sandbox Code Playgroud)

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;
    }
}; 
Run Code Online (Sandbox Code Playgroud)

参考:https://javarevisited.blogspot.com/2011/08/enum-in-java-example-tutorial.html


小智 11

正如您已经注意到的,枚举的第一个好处是语法简单.但是枚举的主要目的是提供一组众所周知的常量,默认情况下,这些常量形成一个范围,并通过类型和值安全检查帮助执行更全面的代码分析.

枚举的这些属性有助于程序员和编译器.例如,假设您看到一个接受整数的函数.整数意味着什么?你能传递什么样的价值观?你真的不知道.但是如果你看到一个接受枚举的函数,你就会非常清楚所有可以传入的值.

对于编译器,枚举有助于确定一系列值,除非您为枚举成员指定特殊值,否则它们的范围从0到更高.这有助于通过类型安全检查等自动跟踪代码中的错误.例如,编译器可能会警告您在switch语句中没有处理所有可能的枚举值(即,当您没有defaultcase并且只处理N个enum值中的一个时).当你将任意整数转换为枚举时,它也会发出警告,因为枚举的值范围小于整数,而这反过来可能会触发函数中不会真正接受整数的错误.此外,当值从0开始时,为开关生成跳转表变得更容易.

这不仅适用于Java,也适用于具有严格类型检查的其他语言.C,C++,D,C#就是很好的例子.


mab*_*abn 7

枚举的好处:

  1. 枚举是类型安全的,静态字段不是
  2. 值的数量是有限的(不可能传递不存在的枚举值。如果你有静态类字段,你可能会犯这个错误)
  3. 每个枚举可以分配多个属性(字段/获取器) - 封装。还有一些简单的方法:YEAR.toSeconds() 或类似的方法。比较:Colors.RED.getHex() 与 Colors.toHex(Colors.RED)

“例如能够轻松地为枚举元素分配某个值”

enum EnumX{
  VAL_1(1),
  VAL_200(200);
  public final int certainValue;
  private X(int certainValue){this.certainValue = certainValue;}
}
Run Code Online (Sandbox Code Playgroud)

“因此无需付出很大的努力就能将整数转换为枚举” Add a method converting int to enum which does that. Just add static HashMap<Integer, EnumX> containing the mapping.

如果您确实想将 ord=VAL_200.ordinal() 转换回 val_200,只需使用: EnumX.values()[ord]


Pet*_*rey 5

枚举是隐式最终的,具有私有构造函数,其所有值都是相同类型或子类型,您可以使用values()获取其所有值,获取其name()ordinal()值,或者您可以按数字或名称查找枚举。

您还可以定义子类(即使名义上是最终的,但您不能以任何其他方式做)

enum Runner implements Runnable {
    HI {
       public void run() {
           System.out.println("Hello");
       }
    }, BYE {
       public void run() {
           System.out.println("Sayonara");
       }
       public String toString() {
           return "good-bye";
       }
    }
 }

 class MYRunner extends Runner // won't compile.
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

108500 次

最近记录:

6 年 前