410013796724260
• Webmoney
R335386147728
Z369087728698
Перечисления enumПри программировании часто необходимо использовать ограниченное множество допустимых значений для некоторого типа данных. Так, например, день недели может иметь 7 разных значений, месяцев в году не более 12, и всего 4 времени года. Для решения подобных задач во многих языках программирования предусмотрен специальный тип данных - перечисление (enum). В Java перечисление enum появилось не сразу только в версии Java 5. Синтаксис перечисления enumОписание с помощью enum типа данных Season для хранения времени года можно представить в следующем виде : enum Season { WINTER, SPRING, SUMMER, AUTUMN } Простой пример использования enum : Season season = Season.WINTER; if (season == Season.WINTER) season = Season.SPRING; System.out.println(season.name()); В результате выполнения данного кода в консоль будет выведен текст SPRING. Перечисление enum - это классПри объявлении переменной типа enum неявно создается класс производный от java.lang.Enum. Условно рассматриваемая конструкция enum Season { ... } эквивалентна class Season extends java.lang.Enum { ... }. Явным образом наследоваться от java.lang.Enum не позволяет компилятор. Но то, что enum наследуется, легко убедиться с помощью reflection: System.out.println(Season.class.getSuperclass()); В консоль будет выведено : class java.lang.Enum Таким образом наследование за разработчика автоматически выполняет компилятор Java. Далее в тексте enum-классом будет называться класс, созданный компилятором для реализации перечисления, а возможные значения перечисляемого типа - элементами enum'a. Элементы перечисления enumЭлементы enum Season (WINTER, SPRING и т.д.) - это статически доступные экземпляры enum-класса Season. Их статическая доступность позволяет выполнять сравнение с помощью оператора сравнения ссылок ==. Например : Season season = Season.SUMMER; if (season == Season.AUTUMN) season = Season.WINTER; Название и порядковый номер элемента enumПример использования методов enum для извлечения информации об объекте : Season season = Season.WINTER; System.out.println("season.name() = " + season.name() + ", season.toString() = " + season.toString() + ", season.ordinal() = " + season.ordinal()); В консоле будет представлено: season.name() = WINTER, season.toString() = WINTER, season.ordinal() = 0 В примере использованы методы name(), toString() и ordinal(). Семантика методов - очевидна. Следует обратить внимание, что данные методы enum-класс наследует от класса java.lang.Enum Получение елемента enum по строковому представлению его имениДовольно часто возникает задача необходимости получения элемента enum по его строковому представлению. Для этих целей в каждом enum-классе компилятор автоматически создает специальный статический метод : public static EnumClass valueOf (String name), который возвращает элемент перечисления EnumClass с названием, равным name. Например: String name = "WINTER"; Season season = Season.valueOf(name); В результате выполнения кода переменная season будет равна Season.WINTER. Получение элементов перечисленияЕсли необходимо получить список всех элементов enum-класса во время выполнения, то для этих целей в следует использовать метод: public static EnumClass[] values(). Например: System.out.println(Arrays.toString(Season.values())); В консоль будет выведено: [WINTER, SPRING, SUMMER, AUTUMN] Необходимо иметь в виду, что ни метод valueOf(), ни метод values() не определены в классе java.lang.Enum. Они автоматически добавляются на этапе компиляции enum-класса. Добавление методов в enum-классМожно добавлять собственные методы как в enum-класс, так и в его элементы: enum Direction { UP, DOWN; public Direction opposite() { return this == UP ? DOWN : UP; } } Тот же пример, но с полиморфизмом: enum Direction { UP { public Direction opposite() { return DOWN; } }, DOWN { public Direction opposite() { return UP; } }; public abstract Direction opposite(); } Наследование в enumС помощью enum в Java можно реализовать иерархию классов, объекты которой создаются в единственном экземпляре и доступны статически. При этом элементы enum могут содержать собственные конструкторы. Пример: enum Type { INT(true) { public Object parse(String string) { return Integer.valueOf(string); } }, INTEGER(false) { public Object parse(String string) { return Integer.valueOf(string); } }, STRING(false) { public Object parse(String string) { return string; } }; boolean primitive; Type(boolean primitive) { this.primitive = primitive; } public boolean isPrimitive() { return primitive; } public abstract Object parse(String string); } Здесь объявляется перечисление Type с тремя элементами INT, INTEGER и STRING. Компилятор создаст следующие классы и объекты:
Три производных класса будут созданы с полиморфным методом Object parse (String) и конструктором Type (..., boolean). При этом объекты классов INT, INTEGER и STRING существуют в единственном экземпляре и доступны статически. В этом можно убедиться, выполнив следующий код : System.out.println(Type.class); System.out.println(Type.INT .getClass() + " " + Type.INT .getClass().getSuperclass()); System.out.println(Type.INTEGER.getClass() + " " + Type.INTEGER.getClass().getSuperclass()); System.out.println(Type.STRING .getClass() + " " + Type.STRING .getClass().getSuperclass()); Результат выполнения кода : class Type class Type$1 class Type class Type$2 class Type class Type$3 class Type Таким образом, компилятор создал класс Type и 3 nested класса, производных от Type. Декомпилированный enum-class с наследованиемВ подтверждение вышесказанному можно привести результат декомпиляции перечисления Type из примера выше: abstract class Type extends Enum { public static Type[] values() { return (Type[]) $VALUES.clone(); } public static Type valueOf(String name) { return (Type) Enum.valueOf(t / T$Type, name); } public boolean isPrimitive() { return primitive; } public abstract Object parse(String s); public static final Type INT; public static final Type INTEGER; public static final Type STRING; boolean primitive; private static final Type $VALUES[]; static { INT = new Type("INT", 0, true) { public Object parse(String string) { return Integer.valueOf(string); } }; INTEGER = new Type("INTEGER", 1, false) { public Object parse(String string) { return Integer.valueOf(string); } }; STRING = new Type("STRING", 2, false) { public Object parse(String string) { return string; } }; $VALUES = (new Type[]{ INT, INTEGER, STRING }); } private Type(String s, int i, boolean primitive) { super(s, i); this.primitive = primitive; } } Перечисления и параметрический полиморфизмМожет возникнуть вопрос: "А почему вышеуказанное перечисление Type не использует generics" ? Причина кроется в том, что в Java использование generics в enum запрещено. Так следующий пример не будет скомпилирован: enum Type<T> {} |