Перечисления в языке Java образуют самостоятельные типы, что указывается словом enum в описании перечисления, но все они неявно наследуют абстрактный класс java.lang.Enum. Это наследование не надо указывать словом extends, как мы обычно делаем, определяя классы. Оно введено только для того, чтобы включить перечисления в иерархию классов Java API. Тем не менее мы можем воспользоваться методами класса Enum для получения некоторых характеристик перечисления, как показано в листинге 3.5.
enum Lights { RED, YELLOW, GREEN, ERROR }
public class EnumMethods{
public static void main(String[] args){ for (Lights light: Lights.values()){
System.out.println("Тип: " + light.getDeclaringClass());
System.out.println("4HcnoBoe значение: " + light.ordinal());
}
}
}
Обратите внимание, во-первых, на то, как задается цикл для перебора всех значений перечисления Lights. В заголовке цикла определяется переменная light типа перечисления Lights. Метод values (), имеющийся в каждом перечислении, дает ссылку на его значения. Эти значения получает последовательно, одно за другим, переменная light.
Во-вторых, посмотрите, как можно узнать тип значений перечисления. Его возвращает метод getDeclaringClass ( ) класса Enum. В случае листинга 3.5 мы получим тип Lights.
В-третьих, у каждой константы, входящей в перечисление, есть свой порядковый номер 0, 1, 2 и т. д. Его можно узнать методом ordinal ( ) класса Enum.
Перечисление — это не только собрание констант. Это полноценный класс, в котором можно определить поля, методы и конструкторы. Мы уже видели, что в каждом перечислении есть методы, унаследованные от класса Enum, например метод values (), возвращающий массив значений перечисления.
Расширим определение перечисления Lights. Для использования его в классе TrafficRegulator нам надо сделать так, чтобы числовое значение константы error было равно -1 и чтобы методом shift() можно было бы получить следующую константу. Этого можно добиться следующим определением:
enum Lights{
RED(0), YELLOW (1), GREEN(2), ERROR(-1); private int value;private int currentValue = 0;
Lights(int value){ this.value = value;} public int getValue(){ return value; }
public Lights nextLight(){
currentValue = (currentValue + 1) % 3; return Lights.values()[currentValue];
}
}
enum Lights{
RED(0), YELLOW (1), GREEN(2), ERROR(-1);
private int value;
private int currentValue = 0;
Lights(int value){ this.value = value;
}
public int getValue(){ return value; }
public Lights nextLight(){
currentValue = (currentValue + 1) % 3; return Lights.values()[currentValue];
}
}
class Timer {
private int delay;
private static Lights light = Lights.RED;
Timer(int sec){
delay = 1000 * sec;
}
public Lights shift(){
Lights count = light.nextLight(); try{
switch (count){
case RED: Thread.sleep(delay); break;
case YELLOW: Thread.sleep(delay/3); break; case GREEN: Thread.sleep(delay/2); break;
}
}catch(Exception e){ return Lights.ERROR;
}
return count;
}
public class TrafficRegulator{
public static void main(String[] args){
Timer t = new Timer(1);
for (int k = 0; k < 10; k++) switch (t.shift()){
case RED: System.out.println("Stop!"); break;
case YELLOW: System.out.println("Wait!"); break; case GREEN: System.out.printlnCWalk!"); break; case ERROR: System.err.println("Time Error"); break; default: System.err.println("Unknown light."); return;
}
}
}
Константы, входящие в перечисление, рассматриваются как константные вложенные классы. Поэтому в них можно определять
Программист может добавить в каждую константу свои поля и методы. В листинге 3.7 приведен известный из документации пример простейшего калькулятора, в котором абстрактный метод выполнения арифметической операции eval () переопределяется в зависимости от ее конкретного вида в каждой константе перечисления Operation.
public enum Operation{ | |||||||||
---|---|---|---|---|---|---|---|---|---|
PLUS { | double | eval(double | x, | double y){ | return | x | + | y; | }}, |
MINUS { | double | eval(double | x, | double y){ | return | x | - | y; | }}, |
TIMES { | double | eval(double | x, | double y){ | return | x | * | y; | }}, |
DIVIDE { | double | eval(double | x, | double y){ | return | x | / | y; | }}; |
abstract double eval(double x, double y); |