Во-вторых, посмотрите, как можно узнать тип значений перечисления. Его возвращает метод 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;
}
}
}
Константы, входящие в перечисление, рассматриваются как константные вложенные классы. Поэтому в них можно определять константно-зависимые поля и методы. Одно такое закрытое поле есть в каждой константе любого перечисления. Оно хранит порядковый номер константы, возвращаемый методом ordinal ().
Программист может добавить в каждую константу свои поля и методы. В листинге 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); | |||||||||
public static void main(String[] args){ double x = -23.567, y = 0.235; for (Operation op: Operation.values())
System.out.println(op.eval(x, y));
}
}
Объявление аннотаций
Аннотации, о которых уже шла речь в главе 1, объявляются интерфейсами специального вида, помеченными символом "at-sign", на жаргоне называемом "собачкой". Например, аннотация @Override, использованная нами в листинге 2.2, может быть объявлена так: public @interface Override{ }
Таково объявление самой простой аннотации — аннотации без элементов (marker annotation). У более сложной аннотации могут быть элементы, описываемые методами интерфейса-аннотации. У этих методов не может быть параметров, но можно задать значение по умолчанию, записываемое после слова default в кавычках и квадратных скобках. Например, следующий текст
public @interface MethodDescription{ int id();
String description() default "[Method]";
String date();
}
объявляет аннотацию с тремя элементами id, name и date. У элемента name есть значение по умолчанию, равное Method.