Номер для каждого элемента перечисления? - PullRequest
7 голосов
/ 29 июля 2010

Можно ли определить что-то подобное в 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?

Ответы [ 5 ]

24 голосов
/ 29 июля 2010

Ну, вы можете почти сделать это:

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...
}

Это может быть полезно в некоторых ситуациях, но, как сказал Майкл, вам непременно следует взглянуть на EnumSet для общих параметров "набора значений".

Если вы делаете решите пойти на перечисление со значениями, вы можете поместить дополнительную логику в самом перечислении:

public enum CharEnum
{
    // Other code as before

    public boolean overlapsWith(CharEnum ch)
    {
        return (ch.mask & mask) > 0;
    }
}
5 голосов
/ 29 июля 2010

(Конечно, выбор Character в качестве имени вашего перечисления очень запутан, поскольку создает конфликт с java.lang.Character, который автоматически импортируется в каждую единицу компиляции)

Вы можете использовать метод ordinal (), чтобы получить целое число, связанное с константой enum. Во всяком случае, у меня сложилось впечатление, что то, что вы пытаетесь достичь, может быть реализовано с помощью перечисленных методов. Я имею в виду, что перечисления в 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) {
     ...
  }
2 голосов
/ 29 июля 2010

Я согласен с Майклом Боргвардтом и Джоном Скитом в том, что стоит посмотреть EnumSet. Я бы выбрал EnumSet для побитовых операций, как у вас, поэтому я покажу, как использовать EnumSet.

Похоже, что ваше Character enum (теперь будем называть его CharEnum) CharEnum используется как битовое поле, где каждое перечисление имеет значение типа 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 не будет уместным. В этом случае вы должны посмотреть на один из других ответов здесь.

2 голосов
/ 29 июля 2010

Я согласен с Itay, и, чтобы продолжить, я рекомендую прочитать Effective Java Second Edition с полной главой, действительно интересной по перечислениям Java.

2 голосов
/ 29 июля 2010

Вы можете сделать что-то подобное, используя Enum.ordinal(), но это будет действительно плохой дизайн. Вы должны использовать == для сравнений на равенство и EnumSet для операций над множествами.

...