【问题标题】:When should I use the final keyword instead of enums?什么时候应该使用 final 关键字而不是枚举?
【发布时间】:2015-04-06 14:58:55
【问题描述】:

我的代码中有以下字段:

private static final int NUM_NANOSECONDS_IN_MILLISECOND = 1000000;

有人告诉我,为了类型安全,我应该为此使用枚举。这不是我熟悉的东西。但如果是这种情况,我不知道什么时候适合在字段上使用 final 关键字。

什么时候应该使用 final 关键字而不是枚举?

【问题讨论】:

  • 为什么枚举在这种情况下甚至有意义?您实际上只有一个值,而不是多个值。这也取决于使用情况;如果您要即时为其添加值,那么您可以考虑在枚举之前添加更多常量。
  • 谁告诉你的?不管是谁,请他们解释并用解释编辑你的问题,因为我也不知道他们在说什么。这听起来像是更适合 C/C++ 的注释。
  • 如果您使用的是 Java 1.4,则没有枚举。否则,枚举通常是更好的选择。尽管对于这种情况下的数字常量,final int 更合理。
  • @EpicPandaForce 啊,所以给他这个建议的人并没有费心去真正阅读他的代码,或者去想它。相反,他看到了private static final int,并像巴甫洛夫的一只狗一样回应。太棒了。
  • 我想知道这个人会对docs.oracle.com/javase/8/docs/api/constant-values.html做出什么反应...

标签: java enums final


【解决方案1】:

常量就是这样,有名字的常量。 枚举是具有值的文字常量。我解释...

考虑:

public final static int NORTH = 0;
public final static int SOUTH = 1;
public final static int EAST = 2;
public final static int WEST = 3;

public enum Direction {
    NORTH, SOUTH, EAST, WEST
}

从可读性的角度来看,它看起来有点相似:

if(direction == NORTH)

或使用枚举:

if(direction == Direction.NORTH)

可能会出错的地方是使用 final 常量,你也可以这样做

if(direction == 0)

现在,即使代码执行相同的操作,也更难理解代码。使用枚举,你就是不能这样做,所以它会出现问题。

同样,当期望一个方向作为方法参数时:

最终静态:

public void myMethod(int direction)

和枚举:

public void myMethod(Direction direction)

更清晰,出现问题的机会更少。

这只是一个开始。枚举实际上可以具有帮助您更好地管理它们包含的信息的方法。阅读here 以获得清晰的解释。

例子:

public enum Direction {
    NORTH (0, 1),
    SOUTH (0, -1),
    EAST (1, 0),
    WEST (-1, 0)

    private int xDirection, yDirection;

    Direction(int x, int y) {
        this.xDirection = x;
        this.yDirection = y;
    }

    public Vector2D getTranslation() {
        return new Vector2D(this.xDirection, this.yDirection);
    }
}

那么在你的代码中:

public void moveThePlayer(Player p, Direction d) {
    p.translate(d.getTranslation());
}

moveThePlayer(p, Direction.NORTH);

final static 很难做到这一点。或者至少,它变得非常难以阅读。

说了这么多,对于您正在使用的特定情况,如果只有一个数字常量值,我会保持最终的静态值。如果只有一个值,则使用枚举毫无意义。

【讨论】:

  • 嘿,翻译的真好。
  • 只是按照我写的来说明这一点,我认为它做得很好。
【解决方案2】:

使用枚举可以避免使用int,而不是final。使用专用枚举提供类型安全,因此您可以拥有更清晰的方法签名并避免错误。 final 用于防止在设置后更改值,无论变量的类型如何,这通常都是一种很好的做法。

但是,在这种情况下,我不确定枚举能给您带来什么价值。 NUM_NANOSECONDS_IN_MILLISECOND 似乎不应该是专用类型,并且正如@BoristheSpider 所建议的那样,您根本不需要该字段。也许您的同事建议对单元使用枚举(例如NANOSECONDMILLISECOND 等),而不是像这样存储比率。在这种情况下,现有的TimeUnit 枚举绝对是你的朋友。

【讨论】:

    【解决方案3】:

    老实说,这取决于您的需求。顾名思义,enum 代表 枚举

    枚举有多个这样的元素

    public enum Colors {
        CYAN, MAGENTA, YELLOW, BLACK
    }
    

    你甚至可以给他们数值左右!因为枚举很酷。

    public enum RGBColors {
        RED(0xFF0000), GREEN(0x00FF00), BLUE(0x0000FF);
    
        private int hexacolor;
    
        private RGBColors(int hexacolor) {
            this.hexacolor = hexacolor;
        }
    
        public int getColorValue() {
            return hexacolor;
        }
    }
    

    您的情况只是一个数字常数。 单个数值常数。

    public static final long SUCH_NUMERICAL_VALUE = 12367160L;
    

    这只是一个常数。这不是枚举。它也没有理由成为枚举,因为您只是将其用作数字。

    enum 的最大优势(在我看来)是您可以迭代其类型的每个元素。

    for(RGBColors rgbColor : RGBColors.values()) {
        ... //do things with rgbColor for each of them
    }
    

    public static final int 无法做到这一点。由于这个问题,我什至在这里写了一个enum 包装器,围绕着一堆public static final 属性:https://stackoverflow.com/a/28295134/2413303

    更重要的是,您无需深入了解源代码即可轻松阅读价值代表什么:

    RGBColors red = RGBColors.RED;
    

    现在让我们用 int 来看看这个:

    int red = RGBColors.RED;
    

    我只能说

    int red = 0; //red color
    

    谁会告诉你以后会发生什么?谁知道呢!

    无论如何,简短的回答是,当您指定 enumerations,也就是多个元素(或者您正在创建枚举单例),这些元素需要有额外的方法或属性。

    public enum MySingleton { //this is an enum singleton
        INSTANCE;
    
        public void doThings() {
            System.out.println("hello!");
        }
    }
    
    MySingleton.INSTANCE.doThings(); //hello!
    

    常量 (public static final) 在您使用它们时非常棒:常量

    【讨论】:

      【解决方案4】:

      我想说,枚举的一般用例是当您有一个小的有限值集,这些值形成了您正在建模的某个集合,并且您将枚举每个值。它们还可以帮助确保应该包含这些值之一的字段不包含其他值。

      在这种情况下,似乎都不适用。你也可以有NUM_NANOSECONDS_IN_MICROSECONDNUM_NANOSECONDS_IN_SECONDNUM_NANOSECONDS_IN_PI_MILLISECONDS,等等,你不会一一列举。此外,您将要存储这些值的变量似乎不应仅限于已定义常量的值。

      【讨论】:

        【解决方案5】:

        在编写源代码时,最好尽可能依靠编译器来帮助您发现逻辑错误。一种方法是使用变量和常量类型,这样如果您在方法中使用了错误的常量,编译器会将其标记为错误。

        该建议并不是关于使用finalenum,因为它们实际上是两个不同的编程概念。相反,它使用enum 创建显式且唯一的类型,而不是使用不那么显式和唯一的int。如果您使用int 作为函数的方法签名的一部分,该函数应该花费纳秒,那么编译器将接受任何int 值。如果您改为使用enum,则仅允许enum 中指定的那些值。使用其他任何东西都会导致编译器发出错误。

        final 关键字是一种确保变量不能被覆盖或修改的方法,以便变量像常量一样工作。 wikipedia article on final.

        enum 中指定的值是常量,因此您可以选择使用现有的常量或使用enum 常量,但是使用enum 将提供来自编译器的安全检查这样只有enum 的指定值才能在纳秒内用于方法调用或变量赋值。

        这是来自堆栈溢出的explanation of final with additional linksJava method keyword final and its use 还提供了一些附加信息。

        有关enum的一些解释请参见What is the purpose of Enum

        【讨论】:

          猜你喜欢
          • 2018-07-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-06-30
          • 2010-10-13
          • 1970-01-01
          • 2019-06-15
          相关资源
          最近更新 更多