Какое преимущество переименования Java в сравнении с классом с публичными статическими конечными полями? - программирование

Какое преимущество переименования Java в сравнении с классом с публичными статическими конечными полями?

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

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

EDIT: Позвольте мне быть более ясным. В чем преимущество перечислений 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);

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

4b9b3361

Ответ 1

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

Ответ 2

  • Введите безопасность и безопасность.
  • Гарантированный синглтон.
  • Возможность определять и переопределять методы.
  • Возможность использования значений в операторах switch statement case без квалификации.
  • Встроенная секвенциализация значений через ordinal().
  • Сериализация по имени не по значению, что обеспечивает степень будущей проверки.
  • EnumSet и EnumMap.

Ответ 3

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

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

Ответ 4

Здесь меньше путаницы. Например, 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. Enums также идеально подходят для singletons и реализуют поведение по умолчанию при одновременном разрешении последующей настройки (IE шаблон стратегии). Примером последнего является java.nio.file OpenOption и StandardOpenOption: если разработчик хотел создать свой собственный нестандартный OpenOption, он мог бы.

Ответ 5

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

Например

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

Ответ 6

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

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

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

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

Ответ 7

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

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

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

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

Ответ 8

пример:

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

Ответ 9

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

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

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

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]

Ответ 10

Перечислимое окончательно, с частными конструкторами, все его значения имеют один и тот же тип или подтип, вы можете получить все его значения с помощью 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.

Ответ 11

Другое важное отличие заключается в том, что компилятор Java обрабатывает static final поля примитивных типов и String как литералы. Это означает, что эти константы становятся встроенными. Это похоже на C/C++ #define препроцессор. Смотри этот ТАК вопрос. Это не относится к перечислениям.

Ответ 12

При использовании перечисления вы получаете время проверки правильности значений. Посмотрите этот вопрос.

Ответ 13

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

public enum EasySingleton{
    INSTANCE;
}

и

/**
* Singleton pattern example with Double checked Locking
*/
public class DoubleCheckedLockingSingleton{
     private volatile DoubleCheckedLockingSingleton INSTANCE;

     private DoubleCheckedLockingSingleton(){}

     public DoubleCheckedLockingSingleton getInstance(){
         if(INSTANCE == null){
            synchronized(DoubleCheckedLockingSingleton.class){
                //double checking Singleton instance
                if(INSTANCE == null){
                    INSTANCE = new DoubleCheckedLockingSingleton();
                }
            }
         }
         return INSTANCE;
     }
}

оба схожи, и они обрабатывали Сериализацию самостоятельно, реализуя

//readResolve to prevent another instance of Singleton
    private Object readResolve(){
        return INSTANCE;
    }

больше

Ответ 14

Я думаю, что enum не может быть final, потому что под капотом компилятор генерирует подклассы для каждой записи enum.

Дополнительная информация Из источника

Ответ 15

Это обычно считается плохой практикой. Проблема в том, что константы являются частью публичного "интерфейса" (из-за лучшего слова) реализующего класса. Это означает, что класс реализации публикует все эти значения для внешних классов, даже если они необходимы только внутренне. Константы распространяются по всему коду. Примером может служить интерфейс SwingConstants в Swing, который реализуется десятками классов, которые все "реэкспортируют" все свои константы (даже те, которые они не используют), как свои собственные. Постоянный шаблон интерфейса плохо использует интерфейсы. То, что класс использует некоторые константы внутри, является деталью реализации. Внедрение постоянного интерфейса приводит к тому, что эта деталь реализации протекает в API-интерфейсе, экспортированном классом. Это не имеет никакого значения для пользователей класса, которые класс реализует постоянный интерфейс. На самом деле это может даже запутать их. Хуже того, он представляет собой обязательство: если в будущей версии класс модифицируется так, что ему больше не нужно использовать константы, он все равно должен реализовать интерфейс для обеспечения совместимости с двоичными файлами. Если нефинальный класс реализует константный интерфейс, все его подклассы будут иметь свои пространства имен, загрязненные константами в интерфейсе.
Перечень может быть лучшим подходом. Или вы можете просто поместить константы в качестве общедоступных статических полей в классе, которые не могут быть созданы. Это позволяет другому классу получить к ним доступ, не загрязняя его собственный API.