【问题标题】:Why "final static int" can be used as a switch's case constant but not "final static <your enum>"为什么“final static int”可以用作开关的大小写常量,但不能用作“final static <your enum>”
【发布时间】:2011-05-23 01:14:57
【问题描述】:

为什么这个 int 开关有效:


public class Foo {
    private final static int ONE = 1;
    private final static int TWO = 2;

    public static void main(String[] args) {
        int value = 1;
        switch (value) {
            case ONE: break;
            case TWO: break;
        }
    }

}

虽然这个枚举开关不是:


import java.lang.annotation.RetentionPolicy;

public class Foo {
    private final static RetentionPolicy RT = RetentionPolicy.RUNTIME;
    private final static RetentionPolicy SRC = RetentionPolicy.SOURCE;

    public static void main(String[] args) {
        RetentionPolicy value = RetentionPolicy.RUNTIME;
        switch (value) {
            case RT: break;
            case SRC: break;
        }
    }

}

我知道这种情况下发生的事情必须是一个常量,那么为什么我可以使用“final static int”作为常量而不是“final static ”?

【问题讨论】:

  • 我为什么要问你想使用静态变量 RT 而不是 RUNTIME?
  • 因为我有一个枚举键 {ZERO, ONE, TWO,...} 代表电话键,并且根据上下文每个键可能意味着一件事或另一件事,所以我用更多声明常量有意义的名字,例如RETURN_TO_MAIN_MENU = Key.ZERO 以便通过阅读案例 RETURN_TO_MAIN_MENU: 而不是案例零:

标签: java enums constants case switch-statement


【解决方案1】:

因为 case 语句标签必须具有编译时间常数或 EnumConstantName。 JLS 14.11

编译时间常数只能是字符串和原始类型,如JLS 15.28 所述。因此,您不能使用静态 final ,因为它既不是编译时常量,也不是枚举的名称。

【讨论】:

    【解决方案2】:

    我有类似的要求,并通过打开枚举序数而不是打开枚举本身来解决这个问题。这不是很漂亮/直观,但它有效:

    public class Foo {
    
        private final static int SRC = 0; // == RetentionPolicy.SOURCE.ordinal();
        private final static int RT = 2; // == RetentionPolicy.RUNTIME.ordinal();
    
        static{
            if (RT != RetentionPolicy.RUNTIME.ordinal() || SRC !=  RetentionPolicy.SOURCE.ordinal()) {
                throw new IllegalStateException("Incompatible RetentionPolicy.class file");
            }
        }
    
        public static void main(String[] args) {
            RetentionPolicy value = RetentionPolicy.RUNTIME;
            switch (value.ordinal()) {
                case RT: break;
                case SRC: break;
            }
        }
    
    }
    

    请注意,当然不可能将常量声明为例如

    private final static int SRC = RetentionPolicy.SOURCE.ordinal();
    

    出于同样的原因,人们一开始就无法将常量声明为枚举...

    【讨论】:

    • 这会起作用,但会产生不确定的连锁反应。例如,如果代码依赖于序数而不是 Enum 值,那么当您插入另一个枚举值时就会遇到麻烦。为清楚起见,请考虑代码可能会被喷溅到哪个期望 SOURCE.ordinal() 为 0。如果将来有人更改 RetentionPolicy,您无法保证这一点。
    • 不完全正确:上面的代码是确定性的,因为静态初始化程序中的运行时检查失败,如果序数由于某种原因发生了变化。当然,这个验证非常重要,不能省略——感谢您指出这个重要的细节!
    【解决方案3】:

    或者简单地使用 if-elseif 案例:

    private final static int ONE = 1;
    private final static int TWO = 2;
    
    public static void main(String[] args) {
        int value = 1;
    
        if(value.equals(ONE)){
    
        }
        else if(value.equals(ONE)){
    
        }
    
    }
    

    【讨论】:

      【解决方案4】:

      编译器说

      unqualified enumeration constant name required
      

      因此,您的 RT 值需要为 RUNTIME 而不是 RetentionPolicy.RUNTIME 才能使您的代码正常工作。但这当然是不可能的。为什么不直接使用RetentionPolicy 枚举?如果你想坚持你的最终静态声明,你需要将整个枚举分配给你的最终静态变量。

      【讨论】:

      • 不理解您的回复。如果您想知道我为什么要这样做,请参阅我添加到帖子中的评论。感谢您的回答。
      【解决方案5】:

      case 参数必须是原始的;它不能是一个对象。

      但是,您可以按如下方式使用枚举:

      RetentionPolicy value = ...
      switch (value) {
          case RUNTIME:
          case SOURCE:
      }
      

      因为value 被声明为RetentionPolicy 类型,所以您可以直接在开关内使用枚举常量。

      【讨论】:

      • RetentionPolicy 一个枚举。
      • @Michael:OP 使用最终静态变量而不是直接引用枚举常量。
      • @Elite:呃……是吗?你有什么问题?
      • 感谢您的回复,但它没有回答我的问题。根据您的示例,我知道如何使用带有枚举的 switch 语句。
      猜你喜欢
      • 2012-06-28
      • 2015-10-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多