Progress-servis55.ru

Новости из мира ПК
4 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Java lang enum

Перечисления enum

При программировании часто необходимо использовать ограниченное множество допустимых значений для некоторого типа данных. Так, например, день недели может иметь 7 разных значений, месяцев в году не более 12, и всего 4 времени года. Для решения подобных задач во многих языках программирования предусмотрен специальный тип данных — перечисление (enum). В Java перечисление enum появилось не сразу только в версии Java 5.

Синтаксис перечисления enum

Описание с помощью enum типа данных Season для хранения времени года можно представить в следующем виде :

Простой пример использования enum :

В результате выполнения данного кода в консоль будет выведен текст SPRING.

Перечисление enum — это класс

При объявлении переменной типа enum неявно создается класс производный от java.lang.Enum. Условно рассматриваемая конструкция enum Season < . >эквивалентна class Season extends java.lang.Enum < . >. Явным образом наследоваться от java.lang.Enum не позволяет компилятор. Но то, что enum наследуется, легко убедиться с помощью reflection:

В консоль будет выведено :

Таким образом наследование за разработчика автоматически выполняет компилятор Java. Далее в тексте enum-классом будет называться класс, созданный компилятором для реализации перечисления, а возможные значения перечисляемого типа — элементами enum’a.

Элементы перечисления enum

Элементы enum Season (WINTER, SPRING и т.д.) — это статически доступные экземпляры enum-класса Season. Их статическая доступность позволяет выполнять сравнение с помощью оператора сравнения ссылок ==. Например :

Название и порядковый номер элемента enum

Пример использования методов enum для извлечения информации об объекте :

В консоле будет представлено:

В примере использованы методы name(), toString() и ordinal(). Семантика методов — очевидна. Следует обратить внимание, что данные методы enum-класс наследует от класса java.lang.Enum

Получение елемента enum по строковому представлению его имени

Довольно часто возникает задача необходимости получения элемента enum по его строковому представлению. Для этих целей в каждом enum-классе компилятор автоматически создает специальный статический метод : public static EnumClass valueOf (String name), который возвращает элемент перечисления EnumClass с названием, равным name. Например:

В результате выполнения кода переменная season будет равна Season.WINTER.
Cледует обратить внимание, что если элемент не будет найден, то будет вызвано исключение IllegalArgumentException, а в случае, если name=nullNullPointerException. Об этом не следует забывать.

Получение элементов перечисления

Если необходимо получить список всех элементов enum-класса во время выполнения, то для этих целей в следует использовать метод: public static EnumClass[] values(). Например:

В консоль будет выведено:

Необходимо иметь в виду, что ни метод valueOf(), ни метод values() не определены в классе java.lang.Enum. Они автоматически добавляются на этапе компиляции enum-класса.

Добавление методов в enum-класс

Можно добавлять собственные методы как в enum-класс, так и в его элементы:

Тот же пример, но с полиморфизмом:

Наследование в enum

С помощью enum в Java можно реализовать иерархию классов, объекты которой создаются в единственном экземпляре и доступны статически. При этом элементы enum могут содержать собственные конструкторы. Пример:

Здесь объявляется перечисление Type с тремя элементами INT, INTEGER и STRING. Компилятор создаст следующие классы и объекты:

  • Type — класс производный от java.lang.Enum
  • INT — объект 1-го класса производного от Type
  • INTEGER — объект 2-го класса производного от Type
  • STRING — объект 3-го класса производного от Type
Читать еще:  Как восстановить значок раскладки клавиатуры windows 7

Три производных класса будут созданы с полиморфным методом Object parse (String) и конструктором Type (. boolean). При этом объекты классов INT, INTEGER и STRING существуют в единственном экземпляре и доступны статически. В этом можно убедиться, выполнив следующий код :

Результат выполнения кода :

Таким образом, компилятор создал класс Type и 3 nested класса, производных от Type.

Декомпилированный enum-class с наследованием

В подтверждение вышесказанному можно привести результат декомпиляции перечисления Type из примера выше:

Перечисления и параметрический полиморфизм

Может возникнуть вопрос: «А почему вышеуказанное перечисление Type не использует generics» ? Причина кроется в том, что в Java использование generics в enum запрещено. Так следующий пример не будет скомпилирован:

Перечисления в Java (Java Enum)

Перечисления (Enum) были введены в Java начиная с версии 1.5 с целью улучшения контроля за типобезопасностью (невозможно назначить переменной значение извне заданного множества допустимых значений). До этого для реализации перечислений предлагалось использовать классы со статическими константами.

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

В результате на консоль будет выведено Черви . Стоит отметить, что перечисления не нужно сравнивать через equals, достаточно сравнения по ссылке.

Одной из наиболее ценной возможностью применения перечислений в Java является использование его внутри оператора switch:

В Java, в отличие от большинства других языков программирования, перечисления представляют собой полноценный класс, наследуемый от java.lang.Enum (наследование автоматически выполняет компилятор Java), в который можно добавлять произвольное количество конструкторов, полей и методов.

java.lang.Enum содержит ряд полезных методов:

  • public final String name() – возвращает задекларированное имя константы.
  • public String toString() – по умолчанию возвращает задекларированное имя константы, однако в отличие от name() может быть переопределен.
  • public final int ordinal() – порядковый номер в котором экземпляр перечисления обозначен внутри enum.
  • public final int compareTo(E o) — имитирует порядок, предоставляемый методом ordinal(). Т.О. enumограничивает сравнения только порядком их объявления.

Так же есть два метода не определенные в классе java.lang.Enum, а добавляемые в процессе компиляции:

  • public static EnumClass valueOf(String name) – возвращает элемент перечисления Enum >public static EnumClass[] values() – возвращает список всех элементов enum-класса.

Важным моментом является факт того, что невозможно создавать экземпляры перечисления вне границ Enum, поскольку у него нет public конструктора, и компилятор не допускает наличие public конструкторов внутри Enum. Экземпляры должны создаваться внутри самого Enum.

Примечание: экземпляр перечисления создается в момент первого обращения к ней.

Пример, охватывающий все вышесказанное:
Результат выполнения:
Наследование и полиморфизм в enum

С помощью Enum в Java можно реализовать иерархию классов, объекты которой создаются в единственном экземпляре и доступные статически.

Например, можно реализовать набор оконных функций для преобразования Фурье (из реального проекта):

Enum в java может реализовывать интефейс, что собственно он уже и делает по умолчанию, реализуя интерфейс Comparable . И именно поэтому Enum по умолчанию может использоваться в упорядоченных коллекциях (например, TreeSet или TreeMap).

Наследовать класс Enum не может, т.к. уже наследуется от java.lang.Enum, а множественного наследования классов в Java нет.

В дополнение стоит указать на наличие в Java Collections API специальных классов EnumSet и EnumMap которые производительнее чем HashSet и HashMap при использовании enum в качестве ключей. По причине того, что если enum содержит не более 64 различных значений, то EnumSet хранит всё в одном поле типа long в битовой маске. А EnumMap хранит все значения в обычном массиве той же длины, сколько элементов в enum (при этом его длинна никогда не изменяется), а ключи не хранит вовсе. Так как у каждого значения в enum есть порядковый номер, получаемый при помощи ordinal().

Перечисления Enum в Java — Часть 2

  • написана командой Vertex Academy. Надеемся, что она Вам будет полезна. Приятного прочтения!
  • это одна из статей из нашего «Самоучителя по Java»
  • Данная статья предполагает, что Вы уже хорошо знаете ООП.

В предыдущей статье ( Урок 66: Перечисления Enum в Java ) мы рассмотрели что такое Enum в Java. Абстрактный класс Enum появился в 5-й версии Java. Теперь, благодаря абстрактному классу Enum мы можем быстро и легко создавать перечисления без написания повторяющегося кода.

В этой статье мы рассмотрим на конкретных примерах следующее:

1. К Enum можно применять методы:

  • name() — возвращает имя
  • ordinal() — возвращает порядковый номер
  • equals()
  • hashCode()
  • toString()
  • finalize()
  • clone()
  • values()
  • valueOf()

2. Enum реализовывает интерфейс Comparable

3. Enum реализовывает интерфейс Serializable

Иииииии сразу в бой 🙂 Создадим простой enum Color

Методы name() и ordinal()

У каждого enum есть имя и порядковый номер. Получить их можно с помощью методов name() и ordinal()

Посмотрим как это реализовано в классе Enum

  • Конструктор невидим для разработчиков, но используется самой Java для корректной работы перечислений.

Возникает вопрос, а где же ключевое слово extends возле декларации перечисления Color? Все дело в ключевом слове enum, именно оно даёт понять программе, что вы хотите не просто класс, а именно перечисление, что и дает Вам уйму возможностей.

Методы equals(), hashcode(), toString(), finalize() и clone()

Enum переопределяет базовые методы класса Object. Так что их можно использовать сразу же в наших перечислениях.

Пример 1: equals()

Пример 2: hashCode()

Поскольку мы использовали hashCode(), каждый раз будет выводиться разное значение, сгенерированное автоматически. Когда мы запускали код, получили числа 366712642 и 1829164700. Вы наверняка получите другие числа.

Пример 3: toString()

Посмотрим как они реализованы в классе Enum

  • метод toString() возвращает имя значения перечисления. Назвали значение WHITE, это же значение и получим при вызове toString() или name();
  • метод equals() сравнивает значения перечислений по ссылкам. Почему? Потому, что значения в перечислениях являются константными (уникальными), существует всего один экземпляр цвета RED, один цвета GREEN и один BLUE, значит ссылка на этот экземпляр будет всего одна, значит их можно сравнивать с помощью ==. Вы можете сами убедиться в этом, написав Color.RED == Color.RED или Color.GREEN == COLOR.BLUE;
  • метод hashCode() использует стандартную реализацию из класса Object.

Пример 4: finalize(), clone()

  • метод finalize() пустой, а это значит, что не нужно закрывать «ресурсы» перед сборщиком мусора. Мы говорим о тех «ресурсах», которые используются в try-with-resources. Да и вообще метод finalize() пережиток прошлых лет и в Java 9 данный метод уже помечен как @Deprecated (устаревший метод, который уберут в последующих реализациях);
  • метод clone() мы можем вызвать только внутри самого перечисления т.к. он помечен ключевым словом protected. Но даже если мы попытаемся сделать это, то ничего мы не получим, кроме CloneNotSupportedException. Нужно это для того чтобы нельзя было создать несколько экземпляров одного и того же перечисления. Ведь в реальной жизни у нас нет двух цифр «1», нет двух значений скорости света, так и с перечислениями.

Метод values() — позволяет получить массив всех значений Enum

Сделать это можно с помощью метода values()

Enum-Всемогущий

Вводная

Предостережение

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

Не рассказанная история.

Однажды попадает разработчик в место, где решают судьбу. Время спустя, перед ним появляется образ и спрашивает:
— Кто ты?
— Я, разработчик, звать Иван, — а про себя: Во встрял то.
Голос опять:
— Хочешь туда?. Взгляд на дверь, за которой рай.
— Ага, — робко Иван.
— Чего поведаешь мне?, — спрашивает Голос.
Немного подумав, Иван начинает говорить:
— Есть в java Enum-Всемогущий.
— Как так, Всемогущий? — перебивает Голос с возмущением. — Это только перечисление!

— Ага, — отвечает разраб, Но не только.
— Докажи!
— Enum как гвозди, утильным могёт.

— Во так чудеса, но… Наследника у него нет!
— А это как посмотреть. А кого считать Наследником? Scala? Kotlin?
— Давай пример, не дожидаясь пока разраб завершит свой вопрос

— Да уж, интересные Вы ребята, прогеры — уже улыбаясь, говорит Голос, — Но малова-то будет
Почесав репу, Иван продолжил:
— Enum-то у нас фабрика!
— Не, было уже.
Пришлось, Ивану последний козырь достать:
— Enum-Синглтон, точно!

Выбери свое

— Джошуа Блох говорит*, что это лучшая реализация Синглтона.
— Ну а ты?
— А что я? Это, это — это синглтон-фабрика, для хранения одного единственного элемента, тить колотить.

Это точка для доступа к массиву для хранения одного единственного элемента, тить колотить.

Это наследник класса . , — хотел было продолжить Иван, но был приятно удивлен:
— Проходи.

Немного выводов

Итого получается, что enum можно наделить следующими качествами и свойствами, в зависимости от точки обзора:

  • Перечисление и данные
  • Каркас для утилитного класса
  • Каркас для синглтона класса + антипатерн прилагается
  • Каркас для фабрики

Эксперимент

Я решил понять, сколько можно максимально сгенерировать элементов перечислений. Мой собственный ответ и реальность настолько разошлись, что я усомнился в своих знаниях. Прежде чем Вы посмотрите ниже, попытайтесь дать ответ самостоятельно. Упростим, скажите хотя бы порядок? Вот код, который я использовал для генерации класса перечислений (на быструю руку):

Вы уже предположили? Так вот, на семерочке мне удалось сгенерировать всего 2746 элементов перечислений. А дальше вот это:

Но, так как я раскатал губу в 4 этажа, сначала я получил такую ошибку:

Ссылка на основную публикацию
Adblock
detector