【问题标题】:Number for each enum item?每个枚举项的编号?
【发布时间】:2010-07-29 07:26:45
【问题描述】:

是否可以在java中定义类似的东西?

C#代码:

public enum Character
{
    A = 1,

    B = 2,

    C = 4,

    D = 8

}


...

Character ch = /* from user */

if(ch & Character.A)
{
    // some operation...
}

例如,如果ch 设置为Character.B,那么if 的结果将是false

ch = 00000000 00000000 00000000 00000010
A  = 00000000 00000000 00000000 00000001
------------------------------------------
&    00000000 00000000 00000000 00000000

我想实现类似的东西! Java有可能吗?

【问题讨论】:

    标签: java integer enums bit-manipulation


    【解决方案1】:

    嗯,你可以几乎做到这一点:

    public enum CharEnum // Let's avoid java.lang.* clashes
    {
        A(1), B(2), C(4), D(8);
    
        private final int mask;
    
        private CharEnum(int mask)
        {
            this.mask = mask;
        }
    
        public int getMask()
        {
            return mask;
        }
    }
    

    然后:

    CharEnum ch = /* from user */
    
    if ((ch.getMask() & CharEnum.A.getMask()) > 0)
    {
        // some operation...
    }
    

    这在某些情况下可能很有用,但正如 Michael 所说,您绝对应该查看 EnumSet 以获得一般的“值集”选项。

    如果您确实决定使用具有值的枚举,则可以在枚举本身中添加额外的逻辑:

    public enum CharEnum
    {
        // Other code as before
    
        public boolean overlapsWith(CharEnum ch)
        {
            return (ch.mask & mask) > 0;
        }
    }
    

    【讨论】:

    • 您应该在此处添加一些括号:if ((ch.getMask() & CharEnum.A.getMask()) > 0)
    【解决方案2】:

    (当然,选择Character 作为枚举的名称是非常令人困惑的,因为它会与自动导入每个编译单元的java.lang.Character 产生冲突)

    您可以使用 ordinal() 方法获取与枚举常量关联的整数。无论如何,我有一种感觉,你想要实现的目标可以通过枚举定义的方法来实现。我的意思是,Java 的枚举比 C/C++ 的更强大,因为您可以将行为与它们关联起来。

      public enum Chr {
        A {
           @Override public void doSomething(int c) {
             // some operation ...
           }
        },
        B,
        C,
        D;
    
        public void doSomething(int c) { 
          // some default behavior
        }
      }
    

    根据您的评论:

    您可以定义一个保存该值的字段,并让构造函数对其进行初始化,如下所示:

      public enum Chr {
        A(1),
        B(2),
        C(4),
        D(8)
        ;
    
        public Chr(int n) { value = n; }        
        public final int value;
      }
    
    
    
      Character ch = ... // from user
      if(ch & Chr.A.value) {
         ...
      }
    

    【讨论】:

      【解决方案3】:

      你可以使用Enum.ordinal() 来做类似的事情,但这将是一个非常糟糕的设计。您应该使用== 进行相等比较,使用EnumSet 进行集合操作。

      【讨论】:

        【解决方案4】:

        我同意 Itay 的观点,为了更进一步,我建议阅读 Effective Java Second Edition,其中有一整章关于 Java 枚举非常有趣。

        【讨论】:

          【解决方案5】:

          我同意 Michael Borgwardt 和 Jon Skeet 的观点,EnumSet 值得一看。我会选择EnumSet 而不是像你这样的按位运算,所以我将演示如何使用EnumSet

           

          看起来你的 Character enum(从现在开始我们称它为CharEnumCharEnum 被用作位字段,其中每个枚举都有一个只有一个的 int 值位组:

          A  = 00000000 00000000 00000000 00000001
          B  = 00000000 00000000 00000000 00000010
          C  = 00000000 00000000 00000000 00000100
          D  = 00000000 00000000 00000000 00001000
          

          这与EnumSet 为您所做的非常相似;它有一个内部位向量,可以自动将每个枚举分配给long 上的一个位。正如它的 JavaDoc 所说,“这个类的空间和时间性能应该足够好,可以作为传统的基于 int 的“位标志”的高质量、类型安全的替代品。

          这是一个如何使用它的示例

          public enum CharEnum {
              A, B, C, D;
          }
          

          然后

          EnumSet<CharEnum> ch = /* from user */
          
          if (ch.contains(CharEnum.A)) {
              // some operation...
          }
          

          无需在任何地方指定位,因此代码更简单!

          警告:这只是因为你的 C# 示例中的枚举值每个都只设置了一个位。如果你有这样的枚举值:

          E  = 00011000 01110111 11100101 10000101
          

          那么EnumSet 就不合适了。在这种情况下,您应该在此处查看其他答案之一。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2013-06-18
            • 1970-01-01
            • 2021-04-01
            • 1970-01-01
            • 2022-10-03
            • 1970-01-01
            • 1970-01-01
            • 2011-04-05
            相关资源
            最近更新 更多