Я очень знаком с C #, но начинаю больше работать на Java. Я ожидал узнать, что перечисления в Java в основном эквивалентны перечислениям в C #, но, очевидно, это не так. Первоначально я был рад узнать, что перечисления Java могут содержать несколько фрагментов данных, что представляется очень полезным ( http://docs.oracle.com/javase/tutorial/java/javaOO/enum.html ). Однако с тех пор я обнаружил, что в C # отсутствуют многие функции, тривиальные, такие как возможность легко назначать элементу enum определенное значение и, следовательно, возможность преобразовать целое число в enum без приличных усилий ( т.е. преобразование целочисленного значения в соответствующее Java Enum ).
Итак, мой вопрос заключается в следующем: есть ли какая-либо польза для перечислений Java по сравнению с классом с множеством открытых статических полей final? Или это просто обеспечивает более компактный синтаксис?
РЕДАКТИРОВАТЬ: Позвольте мне быть более ясным. В чем преимущество перечислений Java над классом с набором открытых статических полей final одного типа ? Например, в примере с планетами в первой ссылке, в чем преимущество перечисления перед классом с этими открытыми константами:
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);
Насколько я могу судить, ответ Касабланки - единственный, который удовлетворяет это.
public static final
поля, которые могут быть типизированными значениями и не обязательноint
s.S
, так что теперь мы говорим о , вероятно , передавая их в функции и т.д. У нас нужно вводить-Техника безопасности? Ну, нет, но тогда большинство людей считают, что типы в стиле c "все этоvoid*
" хороший стиль, и это может остановить ошибки (особенно если передается более одного параметра enum / string!). Кроме того, он помещает константы в их собственное пространство имен и т. Д. В противоположность этому, просто иметь простые переменные не дает реального преимущества.int
s нет безопасности типов, потому что можно передать любое значение. Типизированные объекты, с другой стороны, ничем не отличаются от перечислений с точки зрения безопасности типов.Ответы:
Технически можно действительно рассматривать перечисления как класс с кучей типизированных констант, и именно так константы перечисления реализуются внутри. Использование
enum
однако дает вам полезные методы ( Enum javadoc ), которые в противном случае вам бы пришлось реализовать самостоятельно, такие какEnum.valueOf
.источник
.values()
возможность перебирать список значений.switch
отчетностиcase
заявления без квалификации.ordinal().
EnumSet
иEnumMap
классы.источник
switch
утверждений, которые были исходной мотивацией для использованияEnum
вообще.Никто не упомянул возможность использовать их в
switch
заявлениях; Я добавлю это также.Это позволяет использовать произвольно сложные перечисления чистым способом без использования
instanceof
, потенциально запутанныхif
последовательностей или значений переключения не-string / int. Канонический пример - конечный автомат.источник
Основным преимуществом является безопасность типов. С набором констант может использоваться любое значение того же внутреннего типа, что приводит к ошибкам. С перечислением могут использоваться только применимые значения.
Например
против
источник
setSize(null)
во втором примере, но он, скорее всего, потерпит неудачу гораздо раньше, чем ошибка первого примера.Здесь меньше путаницы. Взять
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
, он мог бы.источник
enum
без использования varargs или aSet
для произвольного числа из них.interface Foo { public void bar(String baz); }
. Кто - то делает класс, вызывающийbar
:someFoo.bar(baz = "hello");
. Я изменяю подписьFoo::bar
наpublic void bar(String foobar)
. Теперь звонившему человекуsomeFoo
нужно будет изменить свой код, если он все еще хочет, чтобы он работал.Здесь есть много хороших ответов, но никто не упоминает, что существуют высоко оптимизированные реализации классов / интерфейсов API Collection специально для перечислений :
Эти специфичные для перечисления классы принимают только
Enum
экземпляры (EnumMap
единственные принимаютEnum
только в качестве ключей), и, когда это возможно, они возвращаются к компактному представлению и манипулированию битами в своей реализации.Что это значит?
Если наш
Enum
тип имеет не более 64 элементов (большинство реальныхEnum
примеров подойдут для этого), реализации сохранят элементы в одномlong
значении, каждыйEnum
рассматриваемый экземпляр будет связан с битом этой 64-битной длиныlong
. Добавление элемента в aEnumSet
- это просто установка правильного бита в 1, удаление - просто установка этого бита в 0. Проверка наличия элемента -Set
это всего лишь один тест битовой маски! Теперь ты должен любить тебяEnum
за это!источник
What does this mean?
раздела. Я знал, что в 64-м размере была разница в реализации, но на самом деле я не знал, почемупример:
Ограничение константы Java
1) Нет безопасности типа : прежде всего, это не тип безопасности; Вы можете присвоить любое действительное значение типа int, например, 99, хотя нет монеты для представления этого значения.
2) Нет значимой печати : при печати значения любой из этих констант будет напечатано ее числовое значение вместо значимого названия монеты, например, когда вы печатаете NICKLE, он напечатает «5» вместо «NICKLE»
3) Нет пространства имен : чтобы получить доступ к константе currencyDenom, нам нужно добавить префикс имени класса, например CurrencyDenom.PENNY, а не просто использовать PENNY, хотя это также может быть достигнуто с помощью статического импорта в JDK 1.5.
Преимущество enum
1) Перечисления в Java являются типобезопасными и имеют собственное пространство имен. Это означает, что ваше перечисление будет иметь тип, например, «Валюта» в приведенном ниже примере, и вы не можете назначать никакие значения, кроме указанных в константах перечисления.
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, см. Пример ниже.
Ссылка: https://javarevisited.blogspot.com/2011/08/enum-in-java-example-tutorial.html
источник
Как вы уже заметили, первое преимущество перечислений - это простота синтаксиса. Но главная задача перечислений - предоставить общеизвестный набор констант, которые по умолчанию образуют диапазон и помогают выполнять более полный анализ кода с помощью проверок безопасности типов и значений.
Эти атрибуты перечислений помогают как программисту, так и компилятору. Например, допустим, вы видите функцию, которая принимает целое число. Что может означать это целое число? Какие ценности вы можете передать? Вы не сразу знаете. Но если вы видите функцию, которая принимает enum, вы очень хорошо знаете все возможные значения, которые вы можете передать.
Для компилятора перечисления помогают определить диапазон значений, и если вы не назначите специальные значения для членов перечисления, они находятся в диапазоне от 0 и выше. Это помогает автоматически отслеживать ошибки в коде с помощью проверок безопасности типов и многого другого. Например, компилятор может предупредить вас, что вы не обрабатываете все возможные значения перечисления в вашем операторе switch (то есть, когда у вас нет
default
регистра и обрабатываете только одно из N значений перечисления). Он также предупреждает вас, когда вы преобразуете произвольное целое число в enum, потому что диапазон значений enum меньше целого, и это, в свою очередь, может вызвать ошибки в функции, которая на самом деле не принимает целое число. Кроме того, создание таблицы переходов для коммутатора становится проще, когда значения начинаются с 0 и выше.Это относится не только к Java, но и к другим языкам со строгой проверкой типов. C, C ++, D, C # являются хорошими примерами.
источник
Перечисление является косвенно конечным, с частными конструкторами, все его значения имеют одинаковый тип или подтип, вы можете получить все его значения, используя
values()
, получает егоname()
илиordinal()
значение, или вы можете искать перечисление по номеру или имени.Вы также можете определить подклассы (даже если условно окончательно, то, что вы не можете сделать другим способом)
источник
Преимущества enum:
«например, возможность легко присвоить элементу enum определенное значение»
«и, следовательно, возможность преобразовать целое число в перечисление без приличных усилий» Добавьте метод, который преобразует int в перечисление, что делает это. Просто добавьте статический HashMap <Integer, EnumX>, содержащий сопоставление java enum .
Если вы действительно хотите преобразовать ord = VAL_200.ordinal () обратно в val_200, просто используйте: EnumX.values () [ord]
источник
Другое важное отличие состоит в том, что компилятор Java обрабатывает
static final
поля примитивных типов и String как литералы. Это означает, что эти константы становятся встроенными. Это похоже наC/C++
#define
препроцессор. Смотрите этот ТАК вопрос . Это не относится к перечислениям.источник
Вы получаете проверку времени компиляции действительных значений при использовании перечисления. Посмотри на этот вопрос.
источник
Самое большое преимущество - enum Singletons просты в написании и поточно-ориентированы:
и
оба похожи, и он обработал сериализацию самостоятельно, реализуя
Больше
источник
Я думаю, что
enum
не может бытьfinal
, потому что под капотом компилятор генерирует подклассы для каждойenum
записи.Больше информации от источника
источник
Есть много преимуществ перечислений, которые размещены здесь, и я создаю такие перечисления прямо сейчас, как задано в вопросе. Но у меня есть перечисление с 5-6 полями.
В таких случаях, когда у вас есть несколько полей в перечислениях, очень трудно понять, какое значение принадлежит какому полю, поскольку вам нужно увидеть конструктор и глазное яблоко.
Класс с
static final
константами и использованиеBuilder
шаблона для создания таких объектов делает его более читабельным. Но вы потеряете все другие преимущества использования enum, если они вам нужны. Одним из недостатков таких классов, вам нужно добавитьPlanet
объекты вручную кlist/set
изPlanets.
Я до сих пор предпочитаю перечисление над таким классом, как
values()
пригождается и вы никогда не знаете , если вам нужны их использовать вswitch
илиEnumSet
илиEnumMap
в будущем :)источник
Основная причина: перечисления помогают вам написать хорошо структурированный код, в котором семантическое значение параметров ясно и строго типизировано во время компиляции - по всем причинам, приведенным в других ответах.
Quid pro quo: в Java «из коробки» массив элементов Enum является окончательным. Обычно это хорошо, поскольку помогает оценить безопасность и тестирование, но в некоторых ситуациях это может быть недостатком, например, если вы расширяете существующий базовый код, возможно, из библиотеки. Напротив, если те же данные находятся в классе со статическими полями, вы можете легко добавить новые экземпляры этого класса во время выполнения (вам также может понадобиться написать код, чтобы добавить их в любой Iterable, который у вас есть для этого класса). Но это поведение Enums может быть изменено: используя отражение, вы можете добавлять новые члены во время выполнения или заменять существующие, хотя это, вероятно, следует делать только в специализированных ситуациях, когда альтернативы нет: то есть это хакерское решение и может привести к неожиданным проблемам, смотри мой ответ наМогу ли я добавлять и удалять элементы перечисления во время выполнения в Java .
источник