==ПредисторияПредыстория==Программируя , мы часто сталкиваемся с необходимостью ограничить множество допустимых значений для некоторого типа данных. Так, например, день недели может иметь 7 разных значений, месяц в году - 12, а время года - 4. Для решения подобных задач во многих языках программирования со статической типизацией предусмотрен специальный тип данных - перечисление <tex>(enum)</tex>.Данный тип данных появился в Java начиная с версии 1.5. (enum) предоставляет множество удобств как в компактности записи, так и в удобстве использования. Так же, по сравнению, допустим, с C++, перечисления в Java представляют собой полноценные объекты, что предоставляет разработчику гораздо большую гибкость.
==Введение ==
В <tex>Java</tex>, начиная с версии 1.5, помимо всего прочего появились так называемые перечисления (enum). Существует целый ряд плюсов от использования перечислений против именованных констант:Компилятор гарантирует корректную проверку типовУдобство итерации по всем возможным значениям перечисленияОни занимают меньше места в <tex>switch-</tex>блоке (не нужно указывать имя класса)и т.д. Однако по сравнению, допустим, с C++, перечисления в Java представляют собой полноценные объекты, что предоставляет разработчику гораздо большую гибкость.Во-первых, все перечисления Перечисления наследуются от класса <tex>java.lang.Enum</tex>, у которого есть ряд удобных методов, а именно. Вот одни из них :
<tex>— name()</tex> — имя константы в виде строки
<tex>— valueOf()</tex> — статический метод, позволяющий получить объект перечисления по классу и имени
Далее, как уже было озвученоТак же, у класса перечисления есть возможность получить все возможные значения перечисления путем вызова метода <tex>java.lang.Class.getEnumConstants()</tex> у класса перечисления.В классе перечисления имеется возможность задавать конструкторы (только приватные), поля и методы. == Перечисление - это класс ==Объявляя enum, мы неявно создаем класс производный от java.lang.Enum. Условно конструкция enum Mark { ... } эквивалентна class Mark extends java.lang.Enum { ... }. Перечисления могут реализовывать любые интерфейсыПри этом методы И хотя явным образом наследоваться от <tex>java.lang.Enum</tex> нам не позволяет компилятор, все же в перечислении могут быть абстрактнымитом, что <tex>enum</tex> наследуется, а конкретные экземпляры констант могут определять такие методы легко убедиться с помощью <tex>reflection:</tex> System.out.println(Mark.class.getSuperclass(как, впрочем, и переопределять уже определенные)); На консоль будет выведено: class java.lang.EnumСобственно наследование за нас автоматически выполняет компилятор Java.
==Конструкция enum==
Начнем с примера. Давайте опишем с помощью enum тип данных для хранения времени годаоценки студента: enum Mark { A, B, C, D, E, F }
Здесь мы использовали новое ключевое слово enum Season { WINTER, SPRINGприсвоили ему имя и указал разрешенные значения. Grade стал перечислимым типом, SUMMERкоторый вы можете использовать, AUTUMN }например, следующим способом:
Ну и простой пример его использования: public class Student { private String Name; private Mark mark; public Student(String Name, Mark mark) { this.Name = Name; this.mark = mark; } public void setName(String Name) { this.Name = Name; } public String getName() { return Name; } public void setMark(Mark mark) { this.mark = mark; } public Mark getMark() { return mark; } }
Season season = SeasonСоздав новое перечисление (Mark) предварительно определенного типа, вы можете использовать его аналогично любой другой переменной экземпляра.SPRING; if Естественно, перечислению можно присвоить только одно из перечисленных значений (season == Season.SPRINGнапример, A, C, или F) season = Season.SUMMER; System.out.printlnОбратите внимание также на то, что в getMark(season);нет кода проверки ошибок на выход за пределы границ.
==Использование enum== ===Итерация по enum===Рассмотрим пример, показывающий, как пройти по значениям любого перечислимого типа. public void PrintAllMarks(PrintStream out) throws IOException { for (Mark mark : Mark.values()) { out.println("Allowed marks : " + mark); } } В результате выполнения которого чего мы получим следующий текст: Allowed marks : A Allowed marks : B Allowed marks : C Allowed marks : D Allowed marks : E Allowed marks : F Так же можно использовать следующую запись для вывода значений на консоль экран: System.out.println(Arrays.toString(Mark.values())); В результате будет выведено SUMMER.: [A, B, C, D, E, F] == Перечисление - это класс =Переключение с enum===Объявляя enum Рассмотренные ранее примеры являются довольно простыми, но перечислимые типы предлагают значительно больше. Перечислимые значения, которые можно использовать для итерации и в операторах <tex>switch</tex>, имеют большое значение. Для сравнения значения mark с разными возможными оценками можно было использовать следующую запись: mark.equals(Mark.A) Но множество сравнений заняло бы много места.Для этого мы неявно создаем класс производный от javaиспользуем <tex>switch</tex>, в результате чего у нас получится: switch (mark) { case A: outputText.append("Great Mark A"); break; case B: // fall through to C case C: outputText.append ("Good Mark ") .append(mark.toString()); break; case D: // fall through to E case E: outputText.append("Bad Mark ") .append(student1.getGrade().toString()); break; case F: outputText.append("Negative Mark F"); break; } В результате чего он выведет соответствующую оценку.langТак же можно употребить <tex>default </tex>, на тот случай, если вдруг другой программист добавил новые значения в Mark, а вас не предупредил.EnumПоставив для варианта <tex>default </tex> вывод сообщения об отсутствии в списке значенияя mark, вы обнаружите это изменение. Условно конструкция ==Получение елемента enum по строковому представлению его имени==Довольно часто возникает задача получить элемент enum Season { по его строковому представлению.Для этих целей в каждом enum-классе компилятор автоматически создает специальный статический метод: public static EnumClass valueOf(String name), который возвращает элемент перечисления EnumClass с названием, равным name.Пример использования: String name = "B"; Mark mark = Mark. } эквивалентна valueOf(name);
class Season extends java.lang.Enum { ... }В результате чего в mark будет записано значение B.
И хотя явным образом наследоваться от <tex>java.lang.Enum</tex> нам не позволяет компилятор==Добавление методов в enum==У Вас есть возможность добавлять собственные методы как в enum-класс, все же так и в томего элементы: enum MarkBool { GOOD, что <tex>BAD; public MarkBool opposite() { return this == GOOD ? BAD : GOOD; } } ==Наследование в enum</tex> наследуется==С помощью enum в Java можно реализовать иерархию классов, легко убедиться с помощью <tex>reflection:</tex>объекты которой создаются в единственном экземпляре и доступны статически. При этом элементы enum могут содержать собственные конструкторы.
System.out.printlnenum MarkBool { GOOD { public MarkBool opposite(Season.class.getSuperclass) { return BAD; } }, BAD { public MarkBool opposite(){ return GOOD; } }; public abstract MarkBool opposite(); }
На консоль Здесь объявляется перечисление MarkBool с двумя элементами BAD и GOOD. Компилятор создаст следующие классы и объекты: •MarkBool - класс производный от java.lang.Enum •BAD - объект 1-го класса производного от MarkBool •GOOD - объект 2-го класса производного от MarkBoolДва производных класса будут созданы с полиморфным методом Object parse(String) и конструктором MarkBool(..., boolean) При этом объекты классов BAD и GOOD существуют в единственном экземпляре и доступны статически. В этом можно убедится: System.out.println(MarkBool.class); System.out.println(MarkBool.BAD.getClass() + " " + MarkBool.BAD.getClass().getSuperclass()); System.out.println(MarkBool.GOOD.getClass() + " " + MarkBool.GOOD.getClass().getSuperclass());Результат будет выведеноследующим: class MarkBool class MarkBool $1 class MarkBool class MarkBool $2 class MarkBool
class java.lang.Enum==Пример==Собственно наследование за нас автоматически выполняет компилятор Java.Раньше класс бинарных операций мы записывали следующим образом:
== Пример ==
Раньше класс бинарные операции мы делали вот так
public class BinaryOperation {
public class Plus {
}
}
Проблема была в том, что пригодилось делать много проверок извне для вызова этих функции. Можно сделать гораздо проще и удобнееС использованием enum все значительно упрощается:
public enum BinaryOperation {
Plus("+") {