9
правок
Изменения
добавлены EnumMap и EnumSet, изменены и добавлены примеры
== Перечисление - это класс ==
Объявляя enum, мы неявно создаем класс производный от java.lang.Enum. Условно конструкция enum Mark Unit { ... } эквивалентна
class Mark Unit extends java.lang.Enum { ... }.
И хотя явным образом наследоваться от <tex>java.lang.Enum</tex> нам не позволяет компилятор, все же в том, что <tex>enum</tex> наследуется, легко убедиться с помощью <tex>reflection:</tex>
System.out.println(MarkUnit.class.getSuperclass());
На консоль будет выведено:
Начнем с примера. Давайте опишем с помощью enum тип данных для хранения оценки студента:
enum Mark Unit { AKILOMETER, BMETER, C, D, E, F MILLIMETER }
Здесь мы использовали новое ключевое слово enum, присвоили ему имя и указал разрешенные значения. Grade Unit стал перечислимым типом, который вы можете использовать, например, следующим способом:
public class Student Distance { private String Namedouble dist; private Mark markUnit unit; public StudentDistance(String Namedouble dist, Mark markUnit unit) { this.Name unit = Nameunit; this.mark dist = markdist;
}
public void setNamesetUnit(String NameUnit unit) { this.Name unit = Nameunit;
}
public String getNameUnit getUnit() { return Nameunit;
}
public void setMarksetDistance (Mark markdouble dist) { this.mark dist = markdist;
}
public Mark getMarkdouble getDistance() { return markdist;
}
}
Создав новое перечисление (MarkUnit) предварительно определенного типа, вы можете использовать его аналогично любой другой переменной экземпляра. Естественно, перечислению можно присвоить только одно из перечисленных значений (например, A, C, или F). Обратите внимание также на то, что в getMarkgetUnit() нет кода проверки ошибок на выход за пределы границ. ==Добавление методов в enum==У Вас есть возможность добавлять собственные методы как в enum-класс, так и в его элементы: enum Unit { KILOMETER(1e3) METER(1) MILLIMETER(1e-3) private final double length; private Unit(double length) { this.length = length } public double getLength() { return length; } } Обратите внимание что использование конструкторов в enum так же доступно, как и в других классах. ==Наследование в enum==С помощью enum в Java можно реализовать иерархию классов, объекты которой создаются в единственном экземпляре и доступны статически. При этом элементы enum могут содержать собственные конструкторы. enum Unit { KILOMETER { public double getLength() { return 1000; } }, METER { public double getLength() { return 1; } }; MILLIMETER { public double getLength() { return 0.001; } }; public abstract double getLength(); } Здесь объявляется перечисление Unit с тремя элементами KILOMETER, METER и MILLIMETER. Компилятор создаст следующие классы и объекты: •Unit - класс производный от java.lang.Enum •KILOMETER - объект 1-го класса производного от Unit •METER - объект 2-го класса производного от Unit •MILLIMETER - объект 3-го класса производного от Unit Два производных класса будут созданы с полиморфным методом Object parse(String) и конструктором Unit(..., boolean). При этом объекты классов KILLOMETER, MILLIMETER и METER существуют в единственном экземпляре и доступны статически. В этом можно убедится: System.out.println(Unit.class); System.out.println(Unit.KILOMETER.getClass() + " " + Unit.KILOMETER.getClass().getSuperclass()); System.out.println(Unit.METER.getClass() + " " + Unit.METER.getClass().getSuperclass()); System.out.println(Unit.MILLIMETER.getClass() + " " + Unit.MILLIMETER.getClass().getSuperclass());Результат будет следующим: class Unit class Unit $1 class Unit class Unit $2 class Unit class Unit $3 class Unit
==Использование enum==
Рассмотрим пример, показывающий, как пройти по значениям любого перечислимого типа.
public void PrintAllMarksPrintAll (PrintStream out) throws IOException { for (Mark mark Unit u1 : MarkUnit.values()) { for (Unit u2 : Unit.values()) { out.println(String.format("Allowed marks : There are %f %sS in one %s" + mark,u2.getLength()/u1.getLength(), u1, u2)); }
}
}
В результате чего мы получим следующий текст:
Так же можно использовать следующую запись для вывода значений на экран:
System.out.println(Arrays.toString(MarkUnit.values()));
В результате будет выведено:
[AKILOMETER, BMETER, C, D, E, FMILLIMETER]
===Переключение с enum===
Рассмотренные ранее примеры являются довольно простыми, но перечислимые типы предлагают значительно больше. Перечислимые значения, которые можно использовать для итерации и в операторах <tex>switch</tex>, имеют большое значение.
Для сравнения значения mark unit с разными возможными оценками можно было мерами длин использовать следующую запись:
Но множество сравнений заняло бы много места.
Для этого мы используем <tex>switch</tex>, в результате чего у нас получитсяследующая запись:
switch (markunit) { case AKILOMETER: outputText.append(return "Great Mark Akm"); break; case B: // fall through to C case C: outputText.append ("Good Mark ") .append(mark.toString()); break; case D: // fall through to E case EMETER: outputText.append(return "Bad Mark m") .append(student1.getGrade().toString()); break; case FMILLIMETER: outputText.append(return "Negative Mark Fmm"); break;
}
В результате чего он выведет соответствующую оценку. Так же можно употребить <tex>default </tex>, на тот случай, если вдруг другой программист добавил новые значения в MarkUnit, а вас не предупредил. Поставив для варианта <tex>default </tex> вывод сообщения об отсутствии в списке значенияя markunit, вы обнаружите это изменение.
==Получение елемента enum по строковому представлению его имени==
Довольно часто возникает задача получить элемент enum по его строковому представлению. Для этих целей в каждом enum-классе компилятор автоматически создает специальный статический метод: public static EnumClass valueOf(String name), который возвращает элемент перечисления EnumClass с названием, равным name. Пример использования:
String name = "BMETER"; Mark mark Unit unit = MarkUnit.valueOf(name);
В результате чего в mark unit будет записано значение BMETER.
==Добавление методов в enumКоллекции перечислимых типов==У Вас есть возможность добавлять собственные методы как В Java использование генериков в enum-класс, так запрещено. Но можно использовать EnumMap и в его элементы:EnumSet. enum MarkBool { GOOD, BAD; public MarkBool opposite() { return this == GOOD ? BAD : GOOD; }=EnumSet=== }Специализированное Set реализация для использования с перечислимыми типами. Все элементы в перечислимом наборе должны прибыть из единственного перечислимого типа, который определяется, явно или неявно, когда набор создается. Перечислимые наборы представляются внутренне как битовый векторы. Это представление чрезвычайно компактно и эффективно.
==Пример==