В чем преимущество перечисления Java по сравнению с классом с открытыми статическими полями final? - PullRequest
128 голосов
/ 02 апреля 2012

Я очень знаком с C #, но начинаю больше работать на Java. Я ожидал узнать, что перечисления в Java в основном эквивалентны перечислениям в C #, но, очевидно, это не так. Вначале я был рад узнать, что перечисления Java могут содержать несколько фрагментов данных, что кажется очень полезным (http://docs.oracle.com/javase/tutorial/java/javaOO/enum.html). Однако с тех пор я обнаружил, что многие функции отсутствуют, которые являются тривиальными в C #, например, возможность легко присваивать элементу enum определенное значение и, следовательно, возможность преобразовывать целое число в перечисление без приличных усилий (т. е. Преобразовать целочисленное значение в соответствующее Enum Java ).

Итак, мой вопрос заключается в следующем: есть ли какая-то польза для перечислений Java по сравнению с классом с множеством открытых статических полей final? Или он просто обеспечивает более компактный синтаксис?

РЕДАКТИРОВАТЬ: Позвольте мне быть более ясным. В чем преимущество перечислений Java над классом с набором открытых статических полей того же типа ? Например, в примере с планетами в первой ссылке, в чем преимущество перечисления перед классом с этими открытыми константами:

public static final Planet MERCURY = new Planet(3.303e+23, 2.4397e6);
public static final Planet VENUS = new Planet(4.869e+24, 6.0518e6);
public static final Planet EARTH = new Planet(5.976e+24, 6.37814e6);
public static final Planet MARS = new Planet(6.421e+23, 3.3972e6);
public static final Planet JUPITER = new Planet(1.9e+27, 7.1492e7);
public static final Planet SATURN = new Planet(5.688e+26, 6.0268e7);
public static final Planet URANUS = new Planet(8.686e+25, 2.5559e7);
public static final Planet NEPTUNE = new Planet(1.024e+26, 2.4746e7);

Насколько я могу судить, ответ Касабланки - единственный, который удовлетворяет этому.

Ответы [ 14 ]

92 голосов
/ 30 сентября 2014
  1. Тип безопасности и значение безопасности.
  2. Гарантированный синглтон.
  3. Возможность определять и переопределять методы.
  4. Возможность использовать значения в switch выражении case в выражениях без квалификации.
  5. Встроенная последовательность значений через ordinal().
  6. Сериализация по имени, а не по значению, что обеспечивает определенную перспективу.
  7. EnumSet и EnumMap классы.
73 голосов
/ 27 декабря 2012

Никто не упоминал о возможности их использования в switch заявлениях;Я добавлю это также.

Это позволяет использовать произвольно сложные перечисления чистым способом без использования instanceof, потенциально путая if последовательностей или значений не-string / int.Каноническим примером является конечный автомат.

73 голосов
/ 02 апреля 2012

Технически можно действительно рассматривать перечисления как класс с кучей типизированных констант, и именно так константы перечисления реализуются внутри. Однако использование enum дает вам полезные методы ( Enum javadoc ), которые в противном случае вам пришлось бы реализовывать самостоятельно, например Enum.valueOf.

42 голосов
/ 02 апреля 2012

Меньше путаницы.Возьмите Font, например.У него есть конструктор, который принимает имя Font, которое вы хотите, его размер и стиль (new Font(String, int, int)).По сей день я не могу вспомнить, идет ли сначала стиль или размер.Если бы Font использовал enum для всех своих различных стилей (PLAIN, BOLD, ITALIC, BOLD_ITALIC), его конструктор выглядел бы как Font(String, Style, int), предотвращая любую путаницу.К сожалению, enum не было, когда был создан класс Font, и, поскольку Java должна поддерживать обратную совместимость, мы всегда будем страдать от этой неоднозначности.

Конечно, это всего лишьаргумент для использования enum вместо public static final констант.Перечисления также идеально подходят для синглетонов и реализуют поведение по умолчанию, допуская последующую настройку (т.е. шаблон стратегии ).Примером последнего является java.nio.file OpenOption и StandardOpenOption: если разработчик хотел создать свой собственный нестандартный OpenOption, он мог бы.

42 голосов
/ 02 апреля 2012

Основным преимуществом является безопасность типов. С набором констант может использоваться любое значение того же внутреннего типа, что приводит к ошибкам. С перечислением могут использоваться только применимые значения.

Например

public static final int SIZE_SMALL  = 1;
public static final int SIZE_MEDIUM = 2;
public static final int SIZE_LARGE  = 3;

public void setSize(int newSize) { ... }

obj.setSize(15); // Compiles but likely to fail later

против

public enum Size { SMALL, MEDIUM, LARGE };

public void setSize(Size s) { ... }

obj.setSize( ? ); // Can't even express the above example with an enum
25 голосов
/ 25 августа 2014

Здесь много хороших ответов, но никто не упоминает, что существует высокооптимизированных реализаций классов / интерфейсов API коллекции специально для перечислений :

Эти специфические для перечисления классы принимают только Enum экземпляры (EnumMap принимает только Enumтолько в качестве ключей), и, когда это возможно, они возвращаются к компактному представлению и манипулированию битами в своей реализации.

Что это значит?

Если наш Enumтип имеет не более 64 элементов (большинство реальных Enum примеров подойдут для этого), реализации хранят элементы в одном значении long, каждый рассматриваемый экземпляр Enum будет связан с битомэто 64-битная длина long.Добавление элемента к EnumSet - это просто установка правильного бита на 1, удаление - просто установка этого бита на 0. Проверка наличия элемента в Set - это всего лишь один тест битовой маски!Теперь ты должен любить Enum s за это!

11 голосов
/ 12 сентября 2014

пример:

public class CurrencyDenom {
   public static final int PENNY = 1;
 public static final int NICKLE = 5;
 public static final int DIME = 10;
public static final int QUARTER = 25;}

Ограничение констант Java

1) Нет безопасности типа : Прежде всего, это небезопасно; Вы можете назначить любое допустимое значение типа int, например, 99, хотя нет монеты, чтобы представить это значение.

2) Нет значимой печати : при печати значения любой из этих констант будет напечатано ее числовое значение вместо значимого имени монеты, например, когда вы печатаете NICKLE, он напечатает «5» вместо «NICKLE»

3) Нет пространства имен : для доступа к константе currencyDenom нам необходимо добавить префикс имени класса, например. CurrencyDenom.PENNY вместо простого использования PENNY, хотя это также может быть достигнуто с помощью статического импорта в JDK 1.5

Преимущество enum

1) Перечисления в Java являются типобезопасными и имеют собственное пространство имен. Это означает, что ваше перечисление будет иметь тип, например, «Валюта» в приведенном ниже примере, и вы не можете назначать никакие значения, кроме указанных в константах перечисления.

public enum Currency {PENNY, NICKLE, DIME, QUARTER};

Currency coin = Currency.PENNY; coin = 1; //compilation error

2) Enum в Java - это ссылочный тип, такой как класс или интерфейс, и вы можете определить конструктор, методы и переменные внутри java Enum, что делает его более мощным, чем Enum в C и C ++, как показано в следующем примере типа Java Enum.

3) Вы можете указать значения констант enum во время создания, как показано в примере ниже: public enum Currency {PENNY (1), NICKLE (5), DIME (10), QUARTER (25)}; Но чтобы это работало, вам нужно определить переменную-член и конструктор, потому что PENNY (1) фактически вызывает конструктор, который принимает значение int, см. Пример ниже.

public enum Currency {
    PENNY(1), NICKLE(5), DIME(10), QUARTER(25);
    private int value;

    private Currency(int value) {
            this.value = value;
    }
}; 

Ссылка: https://javarevisited.blogspot.com/2011/08/enum-in-java-example-tutorial.html

11 голосов
/ 02 апреля 2012

Первое преимущество перечислений, как вы уже заметили, это простота синтаксиса.Но главная задача перечислений - предоставить общеизвестный набор констант, которые по умолчанию образуют диапазон и помогают выполнять более полный анализ кода с помощью проверок безопасности типов и значений.

Эти атрибуты перечислений помогаюти программист, и компилятор.Например, допустим, вы видите функцию, которая принимает целое число.Что может означать это целое число?Какие ценности вы можете передать?Вы не сразу знаете.Но если вы видите функцию, которая принимает enum, вы очень хорошо знаете все возможные значения, которые можете передать.

Для компилятора перечисления помогают определить диапазон значений, и если вы не назначите специальные значения членам перечисления,они хорошо колеблются от 0 и выше.Это помогает автоматически отслеживать ошибки в коде с помощью проверок безопасности типов и многого другого.Например, компилятор может предупредить вас о том, что вы не обрабатываете все возможные значения перечисления в вашем операторе switch (то есть, когда у вас нет регистра default и обрабатываете только одно из N значений перечисления).Он также предупреждает вас, когда вы преобразуете произвольное целое число в enum, потому что диапазон значений enum меньше, чем целое число, и это, в свою очередь, может вызвать ошибки в функции, которая на самом деле не принимает целое число.Кроме того, создание таблицы переходов для коммутатора становится проще, когда значения начинаются с 0 и выше.

Это верно не только для Java, но и для других языков со строгой проверкой типов.C, C ++, D, C # являются хорошими примерами.

4 голосов
/ 02 апреля 2012

Перечисление является косвенно конечным, с частными конструкторами, все его значения имеют одинаковый тип или подтип, вы можете получить все его значения, используя values(), получая его значение name() или ordinal() или Вы можете найти перечисление по номеру или имени.

Вы также можете определить подклассы (хотя условно окончательно, то, что вы не можете сделать другим способом)

enum Runner implements Runnable {
    HI {
       public void run() {
           System.out.println("Hello");
       }
    }, BYE {
       public void run() {
           System.out.println("Sayonara");
       }
       public String toString() {
           return "good-bye";
       }
    }
 }

 class MYRunner extends Runner // won't compile.
4 голосов
/ 02 апреля 2012

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

  1. Перечисления безопасны от типа, статические поля не
  2. Существует конечное число значений (невозможно передать несуществующее значение перечисленияЕсли у вас есть статические поля класса, вы можете совершить эту ошибку)
  3. Каждому перечислению может быть назначено несколько свойств (полей / получателей) - инкапсуляция.Также несколько простых методов: YEAR.toSeconds () или аналогичный.Сравните: Colors.RED.getHex () с Colors.toHex (Colors.RED)

", например, возможность легко присвоить элементу enum определенное значение"

enum EnumX{
  VAL_1(1),
  VAL_200(200);
  public final int certainValue;
  private X(int certainValue){this.certainValue = certainValue;}
}

"и, следовательно, возможность конвертировать целое число в перечисление без приличных усилий" Добавить метод, преобразующий int в enum, который это делает.Просто добавьте статический HashMap, содержащий сопоставление.

Если вы действительно хотите преобразовать ord = VAL_200.ordinal () обратно в val_200, просто используйте: EnumX.values ​​() [ord]

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