Понимание перечислений в Java - PullRequest
14 голосов
/ 14 сентября 2009

Что такое java-перечисления? Как они работают? Где я мог их использовать и как?
Можно ли обойтись без использования перечислений в приложении или они настолько мощные, что их лучше использовать, чем игнорировать?

Ответы [ 6 ]

46 голосов
/ 14 сентября 2009

Перечисления в Java 5+ в основном представляют собой классы, которые имеют предопределенный набор экземпляров. Они предназначены для замены, скажем, набора целочисленных констант. Желательно, чтобы они были постоянными, поскольку они могут обеспечивать безопасность типов.

Так что вместо:

public class Suit {
  public final static int SPADES = 1;
  public final static int CLUBS = 2
  public final static int HEARTS = 3;
  public final static int DIAMONDS = 4;
}

у вас есть:

public enum Suit {
  SPADES, CLUBS, HEARTS, DIAMONDS
}

Преимущества:

  1. Тип безопасности. Вы можете объявить аргумент функции, возвращаемый тип, член класса или локальную переменную как определенный тип Enum, и компилятор обеспечит безопасность типов;
  2. Перечисления в основном классы. Они могут реализовывать интерфейсы, иметь поведение и т. Д.

Безопасность типов является проблемой, поскольку в первом примере это допустимые операторы:

int i = Suit.DIAMONDS * Suit.CLUBS;

или вы можете перейти в 11 к функции, ожидающей иска. Вы не можете сделать это с типизированным перечислением.

Вы можете использовать класс для Suit для обеспечения безопасности типов, и это было решением до Java 5. Джош Блох (в Effective Java , который должен читать для программистов Java imho) продвигал тип перечисления типобезопасности, который стал перечислением Java 5+. Он содержит довольно много шаблонов, и некоторые важные случаи, которые люди не склонны обслуживать, такие как сериализация, не вызывающая конструктор, и чтобы убедиться, что у вас есть только один экземпляр, вы должны переопределить метод readResolve (). *

Например:

public enum CardColour {
  RED, BLACK
}

public enum Suit {
  SPADES(CardColour.BLACK),
  CLUBS(CardColour.BLACK),
  HEARTS(CardColour.RED),
  DIAMONDS(CardColour.RED);

  private final CardColour colour;

  Suit(CardColour colour) { this.colour = colour; }

  public CardColour getColour() { return colour; }
}

Редактировать: У Солнца есть введение в типизированные перечисления .

Что касается интерфейсов, они действительно дополняют перечисления, а не являются альтернативой. Как вы могли бы сказать, что Suit - это интерфейс, и у вас будет это:

public interface Suit {
  CardColour getColour();
}

Проблема в том, что вы можете определить 300 разных мастей, а также несколько раз. Другим преимуществом перечислений является (несмотря на то, что регистр загружается в углу) то, что существует только один экземпляр каждого значения перечисления. Обычно это называется каноническим значением , что означает, что это равенство выполняется:

a.equals(b) == b.equals(a) == (a == b)

для всех a, b, которые являются экземплярами определенного Enum. Это означает, что вместо записи:

if (card.getSuit().equals(Suit.SPADES)) { ... }

Вы можете написать:

if (card.getSuit() == Suit.SPADES) { ... }

, который быстрее и обычно легче для чтения. Кроме того, IDE обычно дают вам обратную связь, если вы сравниваете перечисления разных типов, говоря, что они не могут быть равными, что может быть полезной и ранней формой проверки ошибок.

15 голосов
/ 14 сентября 2009

Думайте об Enum следующим образом

public class MyEnum {

    // Object instantiated at declaration
    public static final MyEnum ONE = new MyEnum();
    public static final MyEnum TWO = new MyEnum();
    public static final MyEnum THREE = new MyEnum();

    // Notice a private constructor 
    // There is no way outside MyEnum class call it
    private MyEnum() { ... }


}

Таким образом, MyEnum как enum будет

public enum MyEnum {
    ONE,
    TWO,
    THREE;
}

Оба похожи

С уважением,

1 голос
/ 04 декабря 2017

Чтобы добавить дополнительную информацию, чтобы узнать больше, лучше начать с понятия переменной и ее значений. Как я уверен, теперь каждая переменная имеет объявленный тип (например, примитивные типы Java). Каждый тип имеет свои соответствующие значения. Например, переменные с типом char могут принимать все отдельные символы в качестве своих значений. Поэтому очень полезно, когда вы хотите объявить, что переменная может принять весь набор символьных констант. Например, все символьные константы являются приемлемыми и значимыми для переменной aCharToStopProgram:

char aCharToStopProgram = getUserInput();

Тем не менее, когда у вас есть ограниченное значение, я имею в виду, что домен значения вашей переменной ограничен специальными значениями. Например, у вас есть userChoice, который сохраняет значение системного вопроса с множественным выбором. Так что просто «а», «б», «в», «г» имеет смысл. Вы не хотите, чтобы в другом разделе кода вашей программы (или по любой другой причине) этой переменной присваивались бессмысленные значения, такие как 's'. Теперь можно использовать тип примитива char для нашей переменной, который может принимать любую символьную константу, например:

char userChoice = getUserChoice();

В этих ситуациях Java предоставляет перечисляемые типы. Это означает, что с помощью ключевого слова enum вы можете определить новый класс с ограниченными и фиксированными экземплярами, который называется именованными значениями (вы не можете создавать новые объекты). Например:

enum MultipleChoiceAnswer { A, B, C, D };

или

public enum MultipleChoiceAnswer {

    A('a'), B('b'), C('c'), D('d');

    private char choice;

    private MultipleChoiceAnswer(char choice) { 
        this.choice = choice; 
    }

    public String getChoice() { 
        return choice; 
    }
}

В результате вы можете определить переменную с вашим собственным типом:

MultipleChoiceAnswer userChoice = getUserChoice();//OR MultipleChoiceAnswer.A      
1 голос
/ 14 сентября 2009

Если ситуация не подходит, значит, они вам не нужны.

Они позволяют вам иметь четко определенный набор вещей, например, если вы хотите представить состояния материи, которые вы можете иметь:

enum MatterState {
    Solid,
    Liquid,
    Gas;
}

Там, где они бьют старый стиль использования объектов для представления множеств различными способами, некоторые из которых:

  • Вы можете использовать их в коммутаторе заявления.
  • Меньше кода.
  • Встроенный в / из строки.
1 голос
/ 14 сентября 2009

Документация Sun enum , вероятно, лучшее объяснение. Конечно, вы можете обойтись без них, как это делали программисты на Java до выпуска Java 1.5. Обычно вы выполняете то же самое, используя константы в версиях Java до 1.5. Но перечисления это приятное удобство.

0 голосов
/ 14 сентября 2009

Из моей интерпретации, перечисления больше для удобства чтения, чем что-либо еще. Они в основном используются для замены значений, таких как 1-6, на более описательные имена, такие как [Happy, Sad, Angry и т. Д.] Вы должны использовать их всякий раз, когда вам нужно использовать небольшой набор переменных для описания ожидаемого решения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...