В перечислении есть метод значений, который используется для генерации массива в порядке, определенном перечислением, который можно использовать для обхода. Все наши пользовательские классы перечисления наследуют от java.lang.Enum и в примерах имеют следующие функции:
Скопируйте код кода следующим образом:
//: перечисляемый/EnumClass.java
// Возможности класса Enum
импортировать статический net.mindview.util.Print.*;
enum Кустарник { ЗЕМЛЯ, ПОЛЗЕНИЕ, ВИСЯЧИЕ }
общественный класс EnumClass {
public static void main(String[] args) {
for(Shrubbery s : Shrubbery.values()) {
print(s + " ordinal: " + s.ordinal());
printnb(s.compareTo(Shrubbery.CRAWLING) + " ");
printnb(s.equals(Кустарник.ПОЛЗАНИЕ) + " ");
print(s == Shrubbery.CRAWLING);
print(s.getDeclaringClass());
печать(s.name());
print("----------------------");
}
// Создание значения перечисления из имени строки:
for(String s : "ВИСЯЩАЯ ПОЛЗАЯ ЗЕМЛЯ".split(" ")) {
Кустарник = Enum.valueOf(Shrubbery.class, s);
печать (кустарник);
}
}
} /* Выход:
ЗЕМЛЯ порядковый номер: 0
-1 ложь ложь
класс Шрабберри
Джошуа Блох оказал огромную помощь в разработке этой главы.
ЗЕМЛЯ
-----------------------
ПОЛЗИРОВАНИЕ порядковый номер: 1
правда правда
класс Шрабберри
ПОЛЗАНИЕ
-----------------------
ВИСЯЩИЙ порядковый номер: 2
ложь ложь
класс Шрабберри
ПОДВЕСКА
-----------------------
ПОДВЕСКА
ПОЛЗАНИЕ
ЗЕМЛЯ
*///:~
Мы также можем использовать статические ссылки перечисления:
Скопируйте код кода следующим образом:
//: перечислено/Spiciness.java
пакет указан;
public enum Spiciness {НЕ, МЯГКИЙ, СРЕДНИЙ, ГОРЯЧИЙ, ПЫЛАЮЩИЙ} ///:~
//: перечислено/Burrito.java
пакет указан;
импорт статического перечисления.Spiciness.*;
общественный класс Буррито {
Степень пряности;
общественное буррито (степень остроты) {this.grade = степень;}
public String toString() { return «Буррито» + степень;}
public static void main(String[] args) {
System.out.println(новый Буррито(НЕ));
System.out.println(новый буррито(СРЕДНИЙ));
System.out.println(новый Буррито(ГОРЯЧИЙ));
}
} /* Выход:
Буррито НЕ
Буррито СРЕДНИЙ
Буррито ГОРЯЧИЙ
*///:~
Помимо добавления в перечисление методов, которые не могут быть унаследованы, перечисление можно рассматривать как общий класс, а это означает, что вы можете добавлять в перечисление методы, а также определять в перечислении основной метод:
Скопируйте код кода следующим образом:
//: перечислено/OzWitch.java
// Ведьмы в стране Оз.
импортировать статический net.mindview.util.Print.*;
публичное перечисление OzWitch {
// Экземпляры должны быть определены первыми, а затем методами:
WEST("Мисс Галч, она же Злая Ведьма Запада"),NORTH("Глинда, Добрая Ведьма Севера"),EAST("Злая Ведьма Востока, носящая Рубин" + "Тапочки, раздавленные Дом Дороти"),ЮГ("Хорошо, но пропало");
описание частной строки;
// Конструктор должен иметь пакетный или частный доступ:
частный OzWitch (описание строки) {
это.описание = описание;
}
общественная строка getDescription () {возвращение описания};
public static void main(String[] args) {
for(OzWitch witch: OzWitch.values())
print(witch + ": " + witch.getDescription());
}
} /* Выход:
ЗАПАД: Мисс Галч, она же Злая Ведьма Запада.
СЕВЕР: Глинда, добрая ведьма Севера.
ВОСТОК: Злая Ведьма Востока, носящая Рубиновые Туфли, раздавленная домом Дороти.
ЮГ: Судя по всему, хорошо, но отсутствует.
*///:~
Скопируйте код кода следующим образом:
//: перечисляется/SpaceShip.java
публичное перечисление SpaceShip {
РАЗВЕДЧИК, ГРУЗОВОЙ, ТРАНСПОРТ, КРЕЙСЕР, ЛИНЕЙНЫЙ КОРАБЛЬ, МАТЕРИНСКИЙ КОРАБЛЬ;
публичная строка toString() {
Идентификатор строки = имя();
Нижняя строка = id.substring(1).toLowerCase();
вернуть id.charAt(0) + ниже;
}
public static void main(String[] args) {
for(SpaceShip s :values()) {
System.out.println(s);
}
}
} /* Выход:
Скаут
Груз
Транспорт
Крейсер
Линкор
Материнский корабль
*///:~
Перечисления в операторах переключения Важная роль перечислений в операторах переключения. Обычно операторы переключения работают только с целочисленными значениями, но в перечислениях имеется встроенный порядок целых чисел, поэтому порядок экземпляров можно определить с помощью какого-либо метода. поэтому перечисления можно использовать в операторах переключения:
Скопируйте код кода следующим образом:
//: перечисляется/TrafficLight.java
// Перечисления в операторах переключения.
импортировать статический net.mindview.util.Print.*;
// Определить тип перечисления:
enum Signal { ЗЕЛЕНЫЙ, ЖЕЛТЫЙ, КРАСНЫЙ, }
общественный класс TrafficLight {
Цвет сигнала = Сигнал.КРАСНЫЙ;
публичное недействительное изменение() {
переключатель (цвет) {
// Обратите внимание: вам не обязательно произносить Signal.RED
// в операторе случая:
корпус КРАСНЫЙ: цвет = Сигнал.ЗЕЛЕНЫЙ;
перерыв;
корпус ЗЕЛЕНЫЙ: цвет = Сигнал.ЖЕЛТЫЙ;
перерыв;
корпус ЖЕЛТЫЙ: цвет = Сигнал.КРАСНЫЙ;
перерыв;
}
}
публичная строка toString() {
возврат «Светофор есть» + цвет;
}
public static void main(String[] args) {
TrafficLight t = новый TrafficLight();
for(int я = 0; я <7; я++) {
печать (т);
т.изменить();
}
}
} /* Выход:
Светофор КРАСНЫЙ
Светофор ЗЕЛЕНЫЙ
Светофор ЖЕЛТЫЙ
Светофор КРАСНЫЙ
Светофор ЗЕЛЕНЫЙ
Светофор ЖЕЛТЫЙ
Светофор КРАСНЫЙ
*///:~
Секрет значений() Хотя раньше мы использовали метод значений, если мы посмотрим на Enum, мы не обнаружим метод значений. Итак, есть ли другие скрытые методы? Мы можем проверить это с помощью простого кода отражения:
Скопируйте код кода следующим образом:
//: перечисление/Reflection.java
// Анализ перечислений с использованием отражения.
импортировать java.lang.reflect.*;
импортировать java.util.*;
импортировать net.mindview.util.*;
импортировать статический net.mindview.util.Print.*;
перечисление Исследуйте { ЗДЕСЬ, ТАМ }
Отражение публичного класса {
public static Set<String> анализ(Class<?> enumClass) {
print("----- Анализ " + enumClass + " -----");
print("Интерфейсы:");
for(Тип t: enumClass.getGenericInterfaces())
печать (т);
print("База: " + enumClass.getSuperclass());
print("Методы: ");
Методы Set<String> = new TreeSet<String>();
for(Метод m: enumClass.getMethods())
методы.add(m.getName());
печать (методы);
методы возврата;
}
public static void main(String[] args) {
Set<String> exploreMethods = анализ(Explore.class);
Set<String> enumMethods = анализ(Enum.class);
print("Explore.containsAll(Enum)? " +
exploreMethods.containsAll(enumMethods));
printnb("Explore.removeAll(Enum): ");
exploreMethods.removeAll(enumMethods);
печать (исследуйте методы);
// Декомпилируем код перечисления:
OSExecute.command("Исследование javap");
}
} /* Выход:
----- Анализ класса Исследовать -----
Интерфейсы:
База: класс java.lang.Enum.
Методы:
[compareTo, равно, getClass, getDeclaringClass, hashCode, name, notify, notifyAll, ordinal, toString, valueOf, значения, подождите]
----- Анализ класса java.lang.Enum -----
Интерфейсы:
java.lang.Comparable<E>
интерфейс java.io.Serializable
База: класс java.lang.Object.
Методы:
[compareTo, равно, getClass, getDeclaringClass, hashCode, name, notify, notifyAll, ordinal, toString, valueOf, подождите]
Explore.containsAll(Enum) правда?
Explore.removeAll(Enum): [значения]
Скомпилировано из "Reflection.java"
последний класс Explore расширяет java.lang.Enum{
публичный статический финал. Исследуйте ЗДЕСЬ;
публичный статический финал Explore THERE;
общедоступные статические окончательные значения Explore[]();
public static Explore valueOf(java.lang.String);
статический {};
}
*///:~
Мы видим, что метод значений добавлен компилятором. Метод valueOf также добавляется компилятором при создании перечисления, но в классе Enum также есть метод valueOf, но этот метод имеет два параметра, тогда как метод valueOf, добавленный компилятором, имеет только один параметр. Перечисления интерпретируются компилятором как окончательные, поэтому перечисления не могут быть унаследованы. Поскольку метод значений — это статический метод, добавленный компилятором, если вы приведете перечисление к Enum, метод значений будет недоступен, но в классе есть метод getEnumConstants, поэтому, хотя метод значений есть недоступен в Enum, но вы все равно можете получить экземпляр перечисления через объект Class:
Скопируйте код кода следующим образом:
//: перечисляемый/UpcastEnum.java
// Нет метода значений(), если вы выполняете преобразование перечисления
перечисление Поиск { СЮДА, ЙОН }
общественный класс UpcastEnum {
public static void main(String[] args) {
Поиск[] vals = Search.values();
Enum e = Search.HITHER // Upcast;
// e.values(); // Нет значений() в Enum
for(Enum en: e.getClass().getEnumConstants())
System.out.println(en);
}
} /* Выход:
СЮДА
ЙОН
*///:~
Реализация без наследования. Поскольку все типы перечислений, которые мы определяем, наследуются от java.lang.Enum, а Java не поддерживает множественное наследование, поэтому перечисления не создаются посредством наследования, но перечисления могут быть созданы путем наследования одного или нескольких интерфейсов:
Скопируйте код кода следующим образом:
//: перечисляемые/мультфильмы/EnumImplementation.java
// Перечисление может реализовать интерфейс
пакет enumerated.cartoons;
импортировать java.util.*;
импортировать net.mindview.util.*;
enum CartoonCharacter реализует Generator<CartoonCharacter> {
СЛЭППИ, СПАНКИ, НАДЕЖНЫЙ, ГЛУПЫЙ, прыгучий, ЧУВСТВЕННЫЙ, БОБ;
частный случайный рандом = новый случайный (47);
общественный CartoonCharacter следующий () {
возвращаемые значения()[rand.nextInt(values().length)];
}
}
общественный класс EnumImplementation {
public static <T> void printNext(Generator<T> rg) {
System.out.print(rg.next() + ", ");
}
public static void main(String[] args) {
// Выбираем любой экземпляр:
CartoonCharacter cc = CartoonCharacter.BOB;
for(int я = 0; я <10; я++)
печатьNext(cc);
}
} /* Выход:
БОБ, ПАНЧИ, БОБ, Спанки, Чокнутый, ПАНЧИ, ШЛЯПНЫЙ, ЧУВСТВЕННЫЙ, ЧУВСТВЕННЫЙ, ШЛЯПНЫЙ,
*///:~
Случайный выбор. Во многих наших примерах ниже мы будем случайным образом выбирать объекты из экземпляров перечисления. Для реализации этого мы создаем общедоступный класс:
Скопируйте код кода следующим образом:
//: net/mindview/util/Enums.java
пакет net.mindview.util;
импортировать java.util.*;
общедоступный класс Enums {
частный статический случайный рандом = новый случайный (47);
public static <T расширяет Enum<T>> T random(Class<T> ec) {
вернуть случайный(ec.getEnumConstants());
}
public static <T> T random(значения T[]) {
возвращаемые значения[rand.nextInt(values.length)];
}
} ///:~
Скопируйте код кода следующим образом:
//: перечисляемый/RandomTest.java
импортировать net.mindview.util.*;
enum Activity { СИДЕНИЕ, ЛЕЖАНИЕ, СТОЯНИЕ, Прыжки, БЕГ, УКЛОНКИ, ПРЫЖКИ, ПАДЕНИЕ, ПОЛЕТ }
общественный класс RandomTest {
public static void main(String[] args) {
for(int я = 0; я <20; я++)
System.out.print(Enums.random(Activity.class) + " ");
}
} /* Выход:
СТОЯ ЛЕТАЮ БЕГ СТОЯ БЕГУ СТОЯ ЛЕЖУ УВЕЛИЧИВАЮСЬ СИДЯ БЕГ СКАЧУЮ СКАЧУЮ БЕГ СТОЯ ЛЕЖА ПАДЕНИЕ БЕГ ЛЕТАЮ
*///:~
Использование интерфейсов для организации перечислений не может быть унаследовано, что иногда доставляет нам неудобства, поскольку иногда мы хотим расширить количество перечислений за счет наследования, а иногда нам нужно сгруппировать перечисления. В последнем случае мы можем определить сгруппированные перечисления в интерфейсе, а затем создать перечисление, унаследовав его от этого интерфейса. Таким образом, у нас есть разные категории продуктов питания, которые необходимо создать как перечисления, но нам нужно определить каждую категорию как типы. продуктов питания следующие:
Скопируйте код кода следующим образом:
//: перечислено/меню/Food.java
// Подкатегоризация перечислений внутри интерфейсов.
пакет enumerated.menu;
общедоступный интерфейс Food {enum Appetizer реализует еду {САЛАТ, СУП, SPRING_ROLLS;}
enum MainCourse реализует Food {LASAGNE, BURRITO, PAD_THAI, LENTILS, HUMMOUS, VINDALOO;}
enum Dessert реализует еду {ТИРАМИСУ, GELATO, BLACK_FOREST_CAKE,FRUIT, CREME_CARAMEL;}
enum Coffee реализует Food {BLACK_COFFEE, DECAF_COFFEE, ESPRESSO,LATTE, CAPPUCCINO, TEA, HERB_TEA;}
} ///:~
Поскольку каждое перечисление определяется как реализация интерфейса, каждое перечисление имеет тип Food следующим образом:
Скопируйте код кода следующим образом:
//: перечисление/меню/TypeOfFood.java
пакет enumerated.menu;
импортировать статический enumerated.menu.Food.*;
общественный класс TypeOfFood {
public static void main(String[] args) {
Еда еда = Закуска.САЛАТ;
еда = MainCourse.LASAGNE;
еда = Десерт.ЖЕЛАТО;
еда = Кофе.КАПУЧИНО;
}
} ///:~
Но интерфейсы не могут работать с несколькими типами, например перечисления, поэтому, если вам нужно перечисление перечислений, вы можете инкапсулировать экземпляр каждого типа перечисления в перечислении:
Скопируйте код кода следующим образом:
//: перечисление/меню/Course.java
пакет enumerated.menu;
импортировать net.mindview.util.*;
публичное перечисление Курс {
ЗАКУСКА(Еда.Закуска.класс),ГЛАВНОЕ(Еда.ОсновноеБлюдо.класс),ДЕСЕРТ(Еда.Десерт.класс),КОФЕ(Еда.Кофе.класс);
частные значения Food[];
частный курс(Класс<? расширяет вид Еда>) {
значения = kind.getEnumConstants();
}
общественная еда randomSelection() {
вернуть Enums.random(значения);
}
} ///:~
Каждое перечисление использует объект Class в качестве соответствующего параметра конструктора. Мы можем использовать getEnumConstants из этого параметра для получения экземпляра перечисления. Этот экземпляр можно использовать в методе randomSelection для генерации случайных блюд:
Скопируйте код кода следующим образом:
//: перечислено/меню/Meal.java
пакет enumerated.menu;
общественный класс Еда {
public static void main(String[] args) {
for(int я = 0; я <5; я++) {
for(Курс курса: Course.values()) {
Еда еда = Конечно.randomSelection();
System.out.println(еда);
}
System.out.println("---");
}
}
} /* Выход:
ВЕСНА_РУЛЛЫ
ВИНДАЛОО
ФРУКТЫ
ДЕКАФ_КОФЕ
---
СУП
ВИНДАЛОО
ФРУКТЫ
ЧАЙ
---
САЛАТ
БУРРИТО
ФРУКТЫ
ЧАЙ
---
САЛАТ
БУРРИТО
КРЕМ_КАРАМЕЛЬ
ЛАТТЕ
---
СУП
БУРРИТО
ТИРАМИСУ
ЭСПРЕССО
---
*///:~
Вот более компактная реализация:
Скопируйте код кода следующим образом:
//: перечисляемый/SecurityCategory.java
// Более краткая подкатегоризация перечислений.
импортировать net.mindview.util.*;
перечисление SecurityCategory {
АКЦИЯ(Ценная бумага.Бонд.класс), ОБЛИГАЦИЯ(Ценная бумага.Бонд.класс);
Значения безопасности[];
SecurityCategory (Class<? расширяет вид Security>) {
значения = kind.getEnumConstants();
}
безопасность интерфейса {
enum Stock реализует Security { SHORT, LONG, MARGIN }
enum Bond реализует безопасность {муниципальный, мусорный}
}
общественная безопасность randomSelection() {
вернуть Enums.random(значения);
}
public static void main(String[] args) {
for(int я = 0; я <10; я++) {
Категория SecurityCategory = Enums.random(SecurityCategory.class);
System.out.println(категория + ": " +
категория.randomSelection());
}
}
} /* Выход:
БОНД: МУНИЦИПАЛЬНЫЙ
БОНД: МУНИЦИПАЛЬНЫЙ
АКЦИИ: МАРЖА
АКЦИИ: МАРЖА
БОНД: МУСОР
АКЦИЯ: КОРОТКИЙ
ЗАПАС: ДЛИННЫЙ
ЗАПАС: ДЛИННЫЙ
БОНД: МУНИЦИПАЛЬНЫЙ
БОНД: МУСОР
*///:~
Скопируйте код кода следующим образом:
//: перечислено/меню/Meal2.java
пакет enumerated.menu;
импортировать net.mindview.util.*;
общественное перечисление Meal2 {
ЗАКУСКА(Еда.Закуска.класс),ГЛАВНОЕ(Еда.ОсновноеБлюдо.класс),ДЕСЕРТ(Еда.Десерт.класс),КОФЕ(Еда.Кофе.класс);
частные значения Food[];
частный Meal2(Class<? расширяет Food> kind) {
значения = kind.getEnumConstants();
}
общедоступный интерфейс Еда {
enum Appetizer реализует еду {SALAD, SOUP, SPRING_ROLLS;}
enum MainCourse реализует Food {LASAGNE, BURRITO, PAD_THAI, LENTILS, HUMMOUS, VINDALOO;}
enum Dessert реализует еду {ТИРАМИСУ, GELATO, BLACK_FOREST_CAKE,FRUIT, CREME_CARAMEL;}
enum Coffee реализует Food {BLACK_COFFEE, DECAF_COFFEE, ESPRESSO,LATTE, CAPPUCCINO, TEA, HERB_TEA;}
}
общественная еда randomSelection() {
вернуть Enums.random(значения);
}
public static void main(String[] args) {
for(int я = 0; я <5; я++) {
for(Meal2 еда : Meal2.values()) {
Еда еда = еда.randomSelection();
System.out.println(еда);
}
System.out.println("---");
}
}
} /* Тот же вывод, что и у Meal.java *///:~
Используйте EnumSet вместо флагов EnumSet был добавлен в Java SE5 для объединения перечислений и наборов для замены битовых флагов на основе целых чисел. Битовые флаги обычно используются для обозначения переключения какой-либо информации, но в коде оперируют битами, а не значимыми понятиями, поэтому их нелегко понять. EnumSet работает быстрее, чем битовые флаги. Он внутренне использует long для представления битового вектора, а затем вы можете использовать более концептуальный язык для представления переключения определенного бита, не беспокоясь об эффективности. Элементы в EnumSet должны происходить из одного и того же перечисления. Следующее определяет перечисление позиции тревоги:
Скопируйте код кода следующим образом:
//: перечисляемый/AlarmPoints.java
пакет указан;
public enum AlarmPoints {STAIR1, STAIR2, LOBBY, OFFICE1, OFFICE2, OFFICE3, OFFICE4, BATHROOM, UTILITY, KITCHEN} ///:~
Затем используйте класс EnumSet для отслеживания статуса сигнала тревоги:
Скопируйте код кода следующим образом:
//: перечисляемый/EnumSets.java
// Операции с EnumSets
пакет указан;
импортировать java.util.*;
импортировать статический enumerated.AlarmPoints.*;
импортировать статический net.mindview.util.Print.*;
общественный класс EnumSets {
public static void main(String[] args) {
EnumSet<AlarmPoints> Points = EnumSet.noneOf(AlarmPoints.class); // Пустой набор
точки.add(ВАННАЯ КОМНАТА);
печать(точки);
Points.addAll(EnumSet.of(ЛЕСТЕНЬ1, ЛЕСТНИЦА2, КУХНЯ));
печать(точки);
точки = EnumSet.allOf(AlarmPoints.class);
Points.removeAll(EnumSet.of(ЛЕСТЕНЬ1, ЛЕСТНИЦА2, КУХНЯ));
печать(точки);
Points.removeAll(EnumSet.range(OFFICE1, OFFICE4));
печать(точки);
точки = EnumSet.complementOf(очки);
печать(точки);
}
} /* Выход:
[ВАННАЯ КОМНАТА]
[ЛЕСТНИЦА 1, ЛЕСТНИЦА 2, ВАННАЯ КОМНАТА, КУХНЯ]
[ЛОББИ, ОФИС 1, ОФИС 2, ОФИС 3, ОФИС 4, ВАННАЯ КОМНАТА, ПОДХОДЫ]
[ВЕСТИ, ВАННАЯ КОМНАТА, ПОДСЛУЖИВАНИЕ]
[ЛЕСТНИЦА1, ЛЕСТНИЦА2, ОФИС1, ОФИС2, ОФИС3, ОФИС4, КУХНЯ]
*///:~
EnumSet построен на длинном типе и имеет 64 бита, так что, если наш тип перечисления превышает это число?
Скопируйте код кода следующим образом:
//: перечисляемый/BigEnumSet.java
импортировать java.util.*;
общественный класс BigEnumSet {
enum Big { A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23 , А24, А25, А26, А27, А28, А29, А30, А31, А32,
А33, А34, А35, А36, А37, А38, А39, А40, А41, А42, А43, А44, А45, А46, А47, А48, А49, А50, А51, А52, А53, А54, А55, А56, А57, А58, А59, А60, А61, А62, А63, А64, А65,
А66, А67, А68, А69, А70, А71, А72, А73, А74, А75}
public static void main(String[] args) {
EnumSet<Big> bigEnumSet = EnumSet.allOf(Big.class);
System.out.println(bigEnumSet);
}
} /* Выход:
[А0, А1, А2, А3, А4, А5, А6, А7, А8, А9, А10, А11, А12, А13, А14, А15, А16, А17, А18, А19, А20, А21, А22, А23, А24 , А25, А26, А27, А28, А29, А30, А31, А32, А33, А34, А35, А36, А37, А38, А39, А40, А41, А42, А43, А44, А45, А46, А47, А48, А49 , А50, А51, А52, А53, А54, А55, А56, А57, А58, А59, А60, А61, А62, А63, А64, А65, А66, А67, А68, А69, А70, А71, А72, А73, А74 , А75]
*///:~
Мы видим, что программа работает нормально, поэтому вполне вероятно, что тип long был добавлен внутри, чтобы помочь разместить тип перечисления с помощью EnumMap.
EnumMap — это особый тип Map. Значение его ключа может быть только типом того же перечисления. По этой причине EnumMap можно реализовать внутри через массив, что очень эффективно.
Скопируйте код кода следующим образом:
//: перечисляемый/EnumMaps.java
// Основы EnumMaps.
пакет указан;
импортировать java.util.*;
импортировать статический enumerated.AlarmPoints.*;
импортировать статический net.mindview.util.Print.*;
Команда интерфейса {void action() };
общественный класс EnumMaps {
public static void main(String[] args) {
EnumMap<AlarmPoints,Command> em = новый EnumMap<AlarmPoints,Command>(AlarmPoints.class);
em.put(КУХНЯ, новая команда() {
public void action() { print("Пожар на кухне!" });
});
em.put(ВАННАЯ КОМНАТА, новая команда() {
public void action() { print("Тревога в ванной!" });
});
for(Map.Entry<AlarmPoints,Command> e : em.entrySet()) {
printnb(e.getKey() + ": ");
e.getValue().action();
}
try { // Если для определенного ключа нет значения:
em.get(UTILITY).action();
} catch(Исключение е) {
печать (е);
}
}
} /* Выход:
ВАННАЯ КОМНАТА: Внимание!
КУХНЯ: Кухня огонь!
java.lang.NullPointerException
*///:~
Конкретные константные методы Перечисления Java имеют очень интересную особенность: для каждого экземпляра перечисления можно определить различное поведение. Чтобы добиться этого, мы определяем один или несколько абстрактных методов как часть перечисления, а затем определяем различное поведение для каждого. Экземпляр перечисления Метод определения экземпляра перечисления:
Скопируйте код кода следующим образом:
//: перечисляемый/ConstantSpecificMethod.java
импортировать java.util.*;
импортировать java.text.*;
общественное перечисление ConstantSpecificMethod {
DATE_TIME {String getInfo() {return DateFormat.getDateInstance().format(new Date());}},
CLASSPATH {String getInfo() {return System.getenv("CLASSPATH");}},
VERSION {String getInfo() {return System.getProperty("java.version");}};
абстрактная строка getInfo();
public static void main(String[] args) {
for(ConstantSpecificMethod csm:values())
System.out.println(csm.getInfo());
}
} /* (Выполните, чтобы увидеть результат) *///:~
Кажется, что приведенный выше код застрял в том, что каждый элемент перечисления является отдельным элементом, и все элементы наследуются от базового класса ConstantSpecificMethod, но мы не можем понять это таким образом, потому что мы не можем рассматривать элементы перечисления как типы:
Скопируйте код кода следующим образом:
//: перечисляемый/NotClasses.java
// {Exec: javap -c LikeClasses}
импортировать статический net.mindview.util.Print.*;
enum LikeClasses {WINKEN { void Behavior() { print("Behavior1" } },BLINKEN { void Behavior() { print("Behavior2" } },NOD { void Behavior() { print("Behavior3"); ; } };
абстрактное недействительное поведение();
}
общественный класс NotClasses {
// void f1(LikeClasses.WINKEN экземпляр) {} // Нет
} /* Выход:
Скомпилировано из "NotClasses.java"
абстрактный класс LikeClasses расширяет java.lang.Enum{
общедоступный статический финал LikeClasses WINKEN;
публичный статический финал LikeClasses BLINKEN;
общедоступный статический финал LikeClasses NOD;
...
*///:~
Рассмотрим другой пример. Клиенты выбирают разные услуги на основе разных меню. Вы можете использовать определенные константные методы, чтобы связать меню с услугами, и использовать EnumSet для сохранения выбора клиента, как показано ниже.
Скопируйте код кода следующим образом:
//: перечислено/CarWash.java
импортировать java.util.*;
импортировать статический net.mindview.util.Print.*;
общественный класс CarWash {
public enum Cycle {UNDERBODY {void action() { print("Опрыскивание днища" }},
WHEELWASH {void action() { print("Мойка колес" }},
ПРЕДВАРИТЕЛЬНАЯ СТИРКА {void action() { print("Разрыхление грязи" }},
BASIC {void action() { print("Базовая стирка" }},
HOTWAX {void action() { print("Нанесение горячего воска" }},
ПРОМЫВКА {void action() { print("Полоскание" }},
BLOWDRY {void action() { print("Сушка" }};
абстрактное действие void();
}
EnumSet<Cycle> Cycles = EnumSet.of(Cycle.BASIC, Cycle.RINSE);
public void add(цикл цикла) {cycles.add(цикл});
общественная недействительная мойкаCar() {
for(Цикл c: циклы)
в.действие();
}
общественная строка toString() { return Cycles.toString() };
public static void main(String[] args) {
Мойка Автомойки = новая Автомойка();
распечатать(стирать);
мыть.мытьмашину();
// Порядок сложения неважен:
стирка.добавить(Цикл.СУШКА БЛОКОМ);
wash.add(Cycle.BLOWDRY); // Дубликаты игнорируются;
стирка.добавить(Цикл.ПОЛОСКАНИЕ);
стирка.добавить(Цикл.HOTWAX);
распечатать(стирать);
мыть.мытьмашину();
}
} /* Выход:
[БАЗОВЫЙ, ПРОМЫВАНИЕ]
Основная стирка
Полоскание
[БАЗОВЫЙ, ГОРЯЧИЙ ВОСК, ПРОМЫВАНИЕ, СУШКА ВОСКОМ]
Основная стирка
Нанесение горячего воска
Полоскание
Сушить
*///:~
Мы также можем переопределить конкретные константные методы по умолчанию вместо использования унаследованных абстрактных методов следующим образом:
Скопируйте код кода следующим образом:
//: перечисляемый/OverrideConstantSpecific.java
импортировать статический net.mindview.util.Print.*;
публичное перечисление OverrideConstantSpecific {
ГАЙКА, БОЛТ, ШАЙБА {void f() { print («Переопределенный метод» }});
void f() { print("поведение по умолчанию" }
public static void main(String[] args) {
for(OverrideConstantSpecific ocs:values()) {
printnb(ocs + ":");
окс.ф();
}
}
} /* Выход:
NUT: поведение по умолчанию
БОЛТ: поведение по умолчанию
ШАЙБА: переопределенный метод
*///:~
Иногда нам нужно передать определенные запросы в цепочке. Зная, что объект в цепочке может обработать запрос, можно легко добиться, используя определенные константные методы. Ниже приведен пример обработки электронных писем.
Скопируйте код кода следующим образом:
//: перечисляется/PostOffice.java
// Моделирование почтового отделения.
Перечислимые типы 743
импортировать java.util.*;
импортировать net.mindview.util.*;
импортировать статический net.mindview.util.Print.*;
класс Почта {
// НЕТ снижают вероятность случайного выбора:
перечисление GeneralDelivery {ДА, НЕТ1, НЕТ2, НЕТ3, НЕТ4, НЕТ5}
enum Сканируемость {НЕСКАНИРОВАНИЕ, ДА1, ДА2, ДА3, ДА4}
перечисление Читабельность {НЕРАЗБОРЧИВО, ДА1, ДА2, ДА3, ДА4}
перечисление Адрес {НЕПРАВИЛЬНО,OK1,OK2,OK3,OK4,OK5,OK6}
перечисление ReturnAddress {MISSING,OK1,OK2,OK3,OK4,OK5}
Общая доставка
Сканируемость, сканируемость;
Читабельность, читабельность;
Адрес адрес;
Адрес возврата returnAddress;
статический длинный счетчик = 0;
длинный идентификатор = счетчик++;
общественная строка toString () {возвращение «Почта» + идентификатор };
сведения о публичной строке() {
return toString() + ", Общая доставка: " + GeneralDelivery + ", Сканируемость адреса: " + сканируемость + ", Читаемость адреса: " + читаемость +
", Адрес Адрес: " + адрес + ", Обратный адрес: " + returnAddress;
}
//Создаем тестовое письмо:
публичная статическая почта randomMail() {
Почта м = новая почта();
m.generalDelivery = Enums.random(GeneralDelivery.class);
m.scannability = Enums.random(Scannability.class);
m.readability = Enums.random(Readability.class);
m.адрес = Enums.random(Адрес.класс);
m.returnAddress = Enums.random(ReturnAddress.class);
вернуть м;
}
public static Iterable<Mail> генератор (окончательный счетчик int) {
вернуть новый Iterable<Mail>() {
int n = количество;
общественный Iterator<Mail> iterator() {
вернуть новый Iterator<Mail>() {
public boolean hasNext() { return n-- > 0 };
общественная почта next() { return randomMail() };
public void Remove() { // Не реализовано
выбросить новое исключение UnsupportedOperationException();
}
};
}
};
}
}
публичный класс PostOffice {
перечисление MailHandler {
ОБЩАЯ_ДОСТАВКА {
логический дескриптор (Почта м) {
переключатель (m.generalDelivery) {
случай ДА:
print("Использование общей доставки для " + m);
вернуть истину;
по умолчанию: вернуть ложь;
}
}
},
МАШИНА_СКАН {
логический дескриптор (Почта м) {
переключатель (m.scannability) {
случай НЕСКАНИРОВАНИЕ: вернуть ложь;
по умолчанию:
переключатель (м.адрес) {
случай НЕПРАВИЛЬНО: вернуть ложь;
по умолчанию:
print("Доставка "+ m + " автоматически");
вернуть истину;
}
}
}
},
ВИЗУАЛ_ИНСПЕКЦИЯ {
логический дескриптор (Почта м) {
переключатель (m.readability) {
регистр НЕРАЗБОРЧИВО: вернуть false;
по умолчанию:
переключатель (м.адрес) {
случай НЕПРАВИЛЬНО: вернуть ложь;
по умолчанию:
print("Доставка " + m + " нормально");
вернуть истину;
}
}
}
},
RETURN_TO_SENDER {
логический дескриптор (Почта м) {
переключатель (m.returnAddress) {
случай MISSING: вернуть false;
по умолчанию:
print("Возврат " + m + " отправителю");
вернуть истину;
}
}
};
абстрактный логический дескриптор (Mail m);
}
static void handle(Mail m) {
for (обработчик MailHandler: MailHandler.values())
если (handler.handle (м))
возвращаться;
print(m + "это мертвая буква");
}
public static void main(String[] args) {
for(Почта почта: Mail.generator(10)) {
печать(mail.details());
дескриптор (почта);
печать("*****");
}
}
} /* Выход:
Почта 0, Обычная доставка: NO2, Возможность сканирования адреса: НЕСКАНИРОВАНИЕ, Читаемость адреса: ДА3, Адресный адрес: OK1, Обратный адрес: OK1
Доставка почты 0 в обычном режиме
*****
Почта 1, Обычная доставка: NO5, Возможность сканирования адреса: ДА3, Читаемость адреса: НЕРАЗБОРЧИВО, Адресный адрес: OK5, Обратный адрес: OK1
Автоматическая доставка почты 1
*****
Почта 2, Обычная доставка: ДА, Возможность сканирования адреса: ДА3, Читаемость адреса: ДА1, Адресный адрес: OK1, Обратный адрес: OK5
Использование общей доставки для Mail 2
*****
Почта 3, Обычная доставка: NO4, Возможность сканирования адреса: ДА3, Читаемость адреса: ДА1, Адресный адрес: НЕПРАВИЛЬНО, Обратный адрес: OK4
Возврат письма 3 отправителю
*****
Почта 4, Обычная доставка: NO4, Сканируемость адреса: НЕСКАНИРОВАНИЕ, Читаемость адреса: ДА1, Адресный адрес: НЕПРАВИЛЬНО, Обратный адрес: OK2
Возврат письма 4 отправителю
*****
Почта 5, Обычная доставка: NO3, Возможность сканирования адреса: ДА1, Читаемость адреса: НЕРАЗБОРЧИВО, Адресный адрес: OK4, Обратный адрес: OK2
Автоматическая доставка Mail 5
*****
Почта 6, Обычная доставка: ДА, Возможность сканирования адреса: ДА4, Читаемость адреса: НЕРАЗБОРЧИВО, Адресный адрес: OK4, Обратный адрес: OK4
Использование общей доставки для Mail 6
*****
Почта 7, Обычная доставка: ДА, Возможность сканирования адреса: ДА3, Читаемость адреса: ДА4, Адресный адрес: OK2, Обратный адрес: ОТСУТСТВУЕТ
Использование общей доставки для Mail 7
*****
Почта 8, Обычная доставка: NO3, Возможность сканирования адреса: ДА1, Читаемость адреса: ДА3, Адресный адрес: НЕПРАВИЛЬНО, Обратный адрес: ОТСУТСТВУЕТ
Mail 8 — мертвое письмо
*****
Почта 9, Обычная доставка: NO1, Возможность сканирования адреса: НЕСКАНИРОВАНИЕ, Читаемость адреса: ДА2, Адресный адрес: OK1, Обратный адрес: OK4
Доставка Mail 9 нормально
*****
*///:~
Тип перечисления также является идеальным типом для создания конечного автомата. Конечный автомат может перемещаться между ограниченным количеством состояний в соответствии с входными данными, а затем завершать работу после достижения определенного состояния. Соответствующий вывод Торговый автомат — это пример типичного конечного автомата, в котором мы определяем различные входные данные внутри перечисления:
Скопируйте код кода следующим образом:
//: перечисляется/Input.java
пакет указан;
импортировать java.util.*;
общедоступное перечисление Ввод {
НИКЕЛЬ(5), ДАЙМ(10), КВАРТАЛ(25), ДОЛЛАР(100),ЗУБНАЯ ПАСТА(200), ЧИПС(75), СОДА(100), МЫЛО(50),ABORT_TRANSACTION {
public int sum() { // Запретить
выбросить новое RuntimeException("ABORT.amount()");
}
},
STOP { // Это должен быть последний экземпляр.
public int sum() { // Запретить
выбросить новое RuntimeException("SHUT_DOWN.amount()");
}
};
целое значение // В центах
Вход (целое значение) { this.value = значение };
Вход() {}
int sum() { возвращаемое значение } // В центах;
статический случайный рандом = новый случайный (47);
публичный статический ввод randomSelection() {
// Не включать СТОП:
возвращаемые значения()[rand.nextInt(values().length - 1)];
}
} ///:~
VendingMachine используется для ответа на ввод. Сначала он классифицирует ввод посредством перечисления категорий, а затем использует оператор переключения:
Скопируйте код кода следующим образом:
//: перечисляется/VendingMachine.java
// {Аргументы: VendingMachineInput.txt}
пакет указан;
импортировать java.util.*;
импортировать net.mindview.util.*;
импортировать статический enumerated.Input.*;
импортировать статический net.mindview.util.Print.*;
перечислить Категория {
ДЕНЬГИ(НИКЕЛЬ, ДАЙМ, КВАРТАЛ, ДОЛЛАР),ITEM_SELECTION(ЗУБНАЯ ПАСТА, ЧИПС, ГАЗАЦИЯ, МЫЛО),QUIT_TRANSACTION(ABORT_TRANSACTION),SHUT_DOWN(STOP);
частные значения Input[];
Категория (Ввод... типы) {значения = типы }
частные статические категории EnumMap<Input,Category> = новый EnumMap<Input,Category>(Input.class);
статический {
for(Категория c: Category.class.getEnumConstants())
for (тип ввода: c.values)
категории.put(тип, c);
}
общественная статическая категория categorize (входной ввод) {
вернуть категории.get(вход);
}
}
общественный класс VendingMachine {
частное статическое состояние State = State.RESTING;
частная статическая сумма int = 0;
частный статический Выбор ввода = null;
enum StateDuration {TRANSIENT} //Тегирование перечисления
перечисление Состояние {
ОТДЫХ {
void next (Входной ввод) {
переключатель (Category.categorize (вход)) {
дело ДЕНЬГИ:
сумма += input.amount();
состояние = ADDING_MONEY;
перерыв;
случай SHUT_DOWN:
состояние = ТЕРМИНАЛ;
по умолчанию:
}
}
},
ADDING_MONEY {
void next (Входной ввод) {
переключатель (Category.categorize (вход)) {
дело ДЕНЬГИ:
сумма += input.amount();
перерыв;
случай ITEM_SELECTION:
выбор = ввод;
если (сумма <выбор.сумма())
print("Недостаточно денег для выбора" +);
иначе состояние = ВЫДАЧА;
перерыв;
случай QUIT_TRANSACTION:
состояние = GIVING_CHANGE;
перерыв;
случай SHUT_DOWN:
состояние = ТЕРМИНАЛ;
по умолчанию:
}
}
},
РАЗДАЧА(StateDuration.TRANSIENT) {
недействительный следующий() {
print("вот ваш " + выбор);
сумма -= выбор.сумма();
состояние = GIVING_CHANGE;
}
},
GIVING_CHANGE(StateDuration.TRANSIENT) {
недействительный следующий() {
если(сумма > 0) {
print("Ваша сдача: " + сумма);
сумма = 0;
}
состояние = ОТДЫХ;
}
},
ТЕРМИНАЛ {void output() {print("Остановлено" }});
частное логическое значение isTransient = false;
Состояние() {}
State (StateDuration trans) {isTransient = true};
void next (Входной ввод) {
throw new RuntimeException("Вызовите " + "next(Input input) только для непереходных состояний");
}
недействительный следующий() {
throw new RuntimeException("Вызов next() только для состояний " + "StateDuration.TRANSIENT");
}
недействительный вывод () {печать (количество);
}
static void run(Generator<Input> gen) {
while(state != State.TERMINAL) {
состояние.следующий(gen.next());
в то время как (state.isTransient)
состояние.следующий();
состояние.выход();
}
}
public static void main(String[] args) {
Generator<Input> gen = новый RandomInputGenerator();
если (args. длина == 1)
gen = новый FileInputGenerator (args [0]);
запустить (ген);
}
}
// Для базовой проверки работоспособности:
класс RandomInputGenerator реализует Generator<Input> {
общественный ввод next() { return Input.randomSelection() };
}
// Создание входных данных из файла строк, разделенных ';':
класс FileInputGenerator реализует Generator<Input> {
частный ввод Iterator<String>;
public FileInputGenerator (String fileName) {
input = новый TextFile(fileName, ";").iterator();
}
публичный ввод next() {
если(!input.hasNext())
вернуть ноль;
return Enum.valueOf(Input.class, input.next().trim());
}
} /* Выход:
вот твои ЧИПЫ
вот твоя ЗУБНАЯ ПАСТА
Ваша сдача: 35
Недостаточно денег на газировку
Недостаточно денег на газировку
Ваша сдача: 75
Остановлено
*///:~
Вот тестовые данные, использованные для генерации приведенного выше вывода:
Скопируйте код кода следующим образом:
ЧЕТВЕРТЬ; ЧИПС;
ДОЛЛАР;
КВАРТАЛ; ПРЕКРАЩЕНИЕ_ТРАНЗАКЦИИ;
ЧЕТВЕРТЬ;
КВАРТАЛ НИКЕЛЬ;
ПРЕКРАЩЕНИЕ_ТРАНЗАКЦИИ;
ОСТАНАВЛИВАТЬСЯ;
///:~
Множественная распаковка При взаимодействии между несколькими типами код, скорее всего, станет беспорядочным, например Number.plush(Number), Number.mutiply(Number) и т. д. Number — это всего лишь базовый класс семейства, поэтому при вызове Когда a.plus(b), вы не знаете ни тип a, ни тип b, так как же гарантировать, что взаимодействие между ними правильное? Java может выполнять только однократную распаковку, то есть, если выполняется одна или несколько операций с несколькими неизвестными типами, Java может выполнить только механизм динамической привязки к одному из типов, что не может решить проблему, о которой мы говорили выше, поэтому у вас есть. чтобы вручную написать код динамической привязки.
Решение — использовать мультипривязку. Полиморфизм может возникнуть только при вызове метода, поэтому если вам нужно несколько распаковок, вам придется вызвать несколько методов. При множественной развертке у вас должен быть виртуальный метод, который вызывает метод каждого типа для развертывания. Следующий пример представляет собой пример «камень-ножницы-бумага»:
Скопируйте код кода следующим образом:
//: перечисляется/Outcome.java
пакет указан;
public enum Outcome { WIN, LOSE, DRAW } ///:~
//: перечисляется/RoShamBo1.java
// Демонстрация множественной диспетчеризации.
пакет указан;
импортировать java.util.*;
импортировать статический enumerated.Outcome.*;
элемент интерфейса {
Результат соревнования(Пункт it);
Оценка результата (Документ р);
Оценка результата(Ножницы);
Оценка результата(Rock r);
}
класс Paper реализует Item {
общественный результат конкурировать (Item it) { return it.eval (this);
общественный результат eval (Paper p) { return DRAW };
общественный результат eval (ножницы) {возврат WIN};
общественный результат eval (Rock r) { return LOSE };
общественная строка toString () {возвращение «Бумага» };
}
класс Scissors реализует Item {
общественный результат конкурировать (Item it) { return it.eval (this);
общественный результат eval (Paper p) { return LOSE };
общественный результат eval (ножницы) { return DRAW };
общественный результат eval (Rock r) {возврат WIN};
public String toString() { return "Ножницы" };
}
класс Rock реализует элемент {
публичный результат соревноваться (Item it) { return it.eval (this);
общественный результат eval (Paper p) { return WIN };
Общественный результат Eval (ножницы s) {return проиграть;
Общественный результат Eval (Rock R) {Return Draw;
public String toString () {return "Rock";
}
открытый класс Roshambo1 {
статический конечный размер int = 20;
частный статический случайный rand = new Random (47);
Public Static Item NewItem () {
Switch (rand.nextint (3)) {
по умолчанию:
Случай 0: вернуть новые ножницы ();
Случай 1: вернуть New Paper ();
Случай 2: вернуть новый рок ();
}
}
Public Static Void Match (пункт A, пункт B) {
System.out.println (a + "против" + b + ":" + a.compete (b));
}
public static void main(String[] args) {
для (int i = 0; i <size; i ++)
match (newitem (), newitem ());
}
} /* Выход:
Рок против рока: рисовать
Бумага против рока: выиграть
Бумага против рока: выиграть
Бумага против рока: выиграть
Ножницы против бумаги: выиграть
Ножницы против ножниц: рисовать
Ножницы против бумаги: выиграть
Рок против бумаги: проиграть
Бумага против бумаги: нарисовать
Рок против бумаги: проиграть
Бумага против ножниц: проиграть
Бумага против ножниц: проиграть
Рок против ножниц: выиграть
Рок против бумаги: проиграть
Бумага против рока: выиграть
Ножницы против бумаги: выиграть
Бумага против ножниц: проиграть
Бумага против ножниц: проиграть
Бумага против ножниц: проиграть
Бумага против ножниц: проиграть
*///: ~
Мы использовали много методов для достижения множественной распаковки, но то, что мы получили, было хорошей структурой кода. Самая большая проблема при использовании решения перечисления для реализации вышеуказанного кода заключается в том, что экземпляр перечисления не является типом, поэтому экземпляр перечисления не может использоваться в качестве типа параметра. Но у нас все еще есть другие способы обойти это препятствие.
Скопируйте код кода следующим образом:
//: перечислен/Roshambo2.java
// переключение одного перечисления на другое.
перечислен упаковки;
Импорт статический перечисление. Outcome.*;
public enum roshambo2 реализует конкурента <srohmbo2> {
Бумага (рисовать, проиграть, выиграть), ножницы (победа, рисовать, проиграть), рок (проиграть, выиграть, рисовать);
Частный результат Vpaper, Vscissors, Vrock;
Roshambo2 (результат бумаги, ножницы результата, результат Rock) {
this.vpaper = paper;
this.vscissors = ножницы;
this.vrock = rock;
}
Государственный результат конкурировать (Roshambo2 It) {
Switch (it) {
по умолчанию:
Кейс -документ: вернуть вежливость;
Ножницы для корпуса: вернуть vscissors;
Case Rock: вернуть Vrock;
}
}
public static void main(String[] args) {
Roshambo.play (Roshambo2.class, 20);
}
} /* Выход:
Рок против рока: рисовать
Ножницы против рока: проиграть
Ножницы против рока: проиграть
Перечисленные типы 753
Ножницы против рока: проиграть
Бумага против ножниц: проиграть
Бумага против бумаги: нарисовать
Бумага против ножниц: проиграть
Рок против ножниц: выиграть
Ножницы против ножниц: рисовать
Рок против ножниц: выиграть
Ножницы против бумаги: выиграть
Ножницы против бумаги: выиграть
Рок против бумаги: проиграть
Рок против ножниц: выиграть
Ножницы против рока: проиграть
Бумага против ножниц: проиграть
Ножницы против бумаги: выиграть
Ножницы против бумаги: выиграть
Ножницы против бумаги: выиграть
Ножницы против бумаги: выиграть
*///: ~
Скопируйте код кода следующим образом:
//: перечислен/конкурент. Java
// переключение одного перечисления на другое.
перечислен упаковки;
конкурент публичного интерфейса <T расширяет конкурентов <T >> {
Результат конкурирует (t конкурента);
} ///: ~
Скопируйте код кода следующим образом:
//: перечислен/roshambo.java
// Общие инструменты для примеров Roshambo.
перечислен упаковки;
Импорт net.mindview.util.*;
открытый класс Roshambo {
public static <t расширяет конкурент <t>> void match (t a, t b) {
System.out.println (a + "против" + b + ":" + a.compete (b));
}
Public Static <T Extens Enum <t> & конкурента <t>> void play (класс <t> rsbclass, int size) {
для (int i = 0; i <size; i ++)
match (enums.random (rsbclass), enums.random (rsbclass));
}
} ///: ~
Поскольку формулирование статических методов может обеспечить различные методы для каждого типа перечисления, это кажется хорошим решением для достижения множественной распаковки, но мы все еще сталкиваемся с проблемой, что экземпляр перечисления не является типом, поэтому все, что мы можем сделать, это добавить оператор переключателя :
Скопируйте код кода следующим образом:
//: перечислен/Росхамбо3.Java
// Использование постоянных методов.
перечислен упаковки;
Импорт статический перечисление. Outcome.*;
public enum roshambo3 реализует конкурента <roshambo3> {
БУМАГА {
государственный результат конкурировать (Roshambo3 It) {
Switch (it) {
по умолчанию: // разместить компилятор
Кейс -статья: вернуть рисунок;
Ножницы для дела: возвращение проиграть;
Case Rock: вернуть победу;
}
}
},
НОЖНИЦЫ {
государственный результат конкурировать (Roshambo3 It) {
Switch (it) {
по умолчанию:
Кейс -документ: вернуть победу;
Кейс -ножницы: вернуть розыгрыш;
Case Rock: возвращение проиграть;
}
}
},
КАМЕНЬ {
государственный результат конкурировать (Roshambo3 It) {
Switch (it) {
по умолчанию:
Случайный документ: вернуть проигрыш;
Ножницы для дела: вернуть победу;
Case Rock: вернуть розыгрыш;
}
}
};
Общественный абстрактный результат конкурирует (Roshambo3 It);
public static void main(String[] args) {
Roshambo.play (Roshambo3.class, 20);
}
}/ * Тот же результат, что и Roshambo2.java * ///: ~
Следующий код является более кратким методом реализации:
Скопируйте код кода следующим образом:
//: перечислил/Росхамбо4.Java
перечислен упаковки;
public enum roshambo4 реализует конкурента <roshambo4> {
КАМЕНЬ {
Государственный результат конкурировать (Oppontent Roshambo4) {
return Compete (ножницы, противник);
}
},
НОЖНИЦЫ {
Государственный результат конкурировать (Oppontent Roshambo4) {
вернуть конкуренцию (бумага, противник);
}
},
БУМАГА {
Государственный результат конкурировать (Oppontent Roshambo4) {
return Compete (Rock, Oppent);
}
};
Результат конкурировать (Roshambo4 Lofer, Opponent Roshambo4) {
return ((противник == this)? reface.draw: ((противник == неудачник)? REUTCOME.WIN: REUTCOME.LOSE));
}
public static void main(String[] args) {
Roshambo.play (Roshambo4.class, 20);
}
}/ * Тот же результат, что и Roshambo2.java * ///: ~
Класс Enummap, кажется, является хорошим способом реализовать множественные распаковки:
Скопируйте код кода следующим образом:
//: перечислен/Росхамбо5.Java
// множественная отправка с использованием Enummap of Enummaps.
перечислен упаковки;
импортировать java.util.*;
Импорт статический перечисление. Outcome.*;
enum roshambo5 реализует конкурента <roshambo5> {
Бумага, ножницы, камень;
static enummap <roshambo5, enummap <roshambo5, результат >> table = new enummap <roshambo5, enummap <roshambo5, результат >> (Roshambo5.class);
статический {
для (Roshambo5 It: Roshambo5.values ())
table.put (it, new enummap <roshambo5, результат> (roshambo5.class));
initrow (бумага, рисовать, проиграть, выиграть);
initrow (ножницы, победа, рисовать, проиграть);
initrow (рок, проиграть, выиграть, рисовать);
}
static void initrow (roshambo5 it, vpaper vpaper, результат vscissors, результат vrock) {
Enummap <roshambo5, результат> row = roshambo5.table.get (it);
row.put (Roshambo5.paper, Vpaper);
row.put (Roshambo5.scissors, Vscissors);
row.put (roshambo5.rock, vrock);
}
государственный результат конкурировать (Roshambo5 It) {
return table.get (this) .get (it);
}
public static void main(String[] args) {
Roshambo.play (Roshambo5.class, 20);
}
}/ * Тот же результат, что и Roshambo2.java * ///: ~
Мы также можем использовать функцию экземпляров перечисления с фиксированными значениями для использования данных для простейшего метода реализации.
Скопируйте код кода следующим образом:
//: перечислен/Roshambo6.java
// перечисляет, используя «таблицы» вместо нескольких диспетчеров.
перечислен упаковки;
Импорт статический перечисление. Outcome.*;
enum roshambo6 реализует конкурента <roshambo6> {
Бумага, ножницы, камень;
частный статический результат [] [] Таблица = {
{Нарисовать, проиграть, выиграть}, // бумага
{Выиграть, рисовать, проиграть}, // ножницы
{Проиграть, выиграть, рисовать}, // рок
};
Государственный результат конкурировать (Roshambo6 Другое) {
return Table [this.ordinal ()] [shere.ordinal ()];
}
public static void main(String[] args) {
Roshambo.play (Roshambo6.class, 20);
}
} ///: ~