Понимание перечислений в Java

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

Ответ 1

Перечисления в 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; }
}

Изменить: Sun предлагает введение в безопасные типы.

Что касается интерфейсов, они действительно дополняют перечисления, а не являются альтернативой. Как вы могли бы сказать, что 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, как правило, дают вам обратную связь, если вы сравниваете перечисления разных типов, говоря, что они не могут быть равными, что может быть полезной и ранней формой проверки ошибок.

Ответ 2

Подумайте об 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 в качестве перечисления будет

public enum MyEnum {
    ONE,
    TWO,
    THREE;
}

Оба являются похожими

С уважением,

Ответ 3

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

Ответ 4

Если ситуация не возникает, вам не нужны.

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

enum MatterState {
    Solid,
    Liquid,
    Gas;
}

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

  • Вы можете использовать их в коммутаторе заявления.
  • Меньше кода.
  • Встроенный to/from string.

Ответ 5

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

char aCharToStopProgram = getUserInput();

Однако, как насчет того, когда у вас ограниченное значение, я имею в виду, что область значений вашей переменной ограничена специальными значениями. Например, у вас есть userChoice, который сохраняет значение системного вопроса с множественным выбором. Таким образом, просто "a", "b", "c", "d" имеет смысл. Вы не хотите в другом разделе вашего программного кода (или по любой другой причине) этой переменной присваиваются бессмысленные значения, такие как '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      

Ответ 6

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

Ответ 7

Java Enum - это специальный тип Java, используемый для определения коллекций констант. Точнее, тип перечисления Java - это особый вид класса Java. Перечисление может содержать константы, методы и т.д. Перечисления Java были добавлены в Java 5.

public enum Level {
    HIGH,
    MEDIUM,
    LOW
}

Bytecode:

public final enum package/Level extends java/lang/Enum  {

  // compiled from: Level.java

  public final static enum package/Level; HIGH
  public final static enum package/Level; MEDIUM
  public final static enum package/Level; LOW

  //...
}

Перечисления Java неявно расширяют класс java.lang.Enum, поэтому типы перечислений не могут расширять другой класс.

Если перечисление Java содержит поля и методы, определение полей и методов всегда должно идти после списка констант в перечислении. Кроме того, список констант enum должен заканчиваться точкой с запятой ;

EnumSet - Java содержит специальную реализацию Java Set, называемую EnumSet, которая может хранить перечисления более эффективно, чем стандартные реализации Java Set.[About]

EnumMap - Java также содержит специальную реализацию Java Map, которая может использовать экземпляры перечисления Java в качестве ключей.[EnumMap vs HashMap]

Официальный Android документ

Избегайте перечислений
Одноперечисление может добавить от 1,0 до 1,4 КБ в файл вашего приложения classes.dex. Эти дополнения могут быстро накапливаться для сложных систем или общих библиотек. Если возможно, рассмотрите возможность использования аннотации @IntDef и ProGuard, чтобы вырезать перечисления и преобразовать их в целые числа. Это преобразование типов сохраняет все преимущества перечислений для безопасности типов.

Подробнее здесь, здесь, здесь