:notebook: Эта статья была заархивирована в: "blog"
:keyboard: Пример кода в этой статье был заархивирован в: "javacore"
Введение
enum
Полное имя перечисления — это функция, представленная в JDK5.
В Java, поenum
Тип, измененный ключевым словом, является типом перечисления. Форма выглядит следующим образом:
enum ColorEn { RED, GREEN, BLUE }
Преимущества перечисления: Константы могут быть организованы и управляться единообразно.
Типичные сценарии применения для перечисления: код ошибки, конечный автомат и т. д.
Перечисление природы
java.lang.Enum
Декларация класса
public abstract class Enum<E extends Enum<E>>
implements Comparable<E>, Serializable { ... }
Создайте новый файл ColorEn.java со следующим содержимым:
package io.github.dunwu.javacore.enumeration;
public enum ColorEn {
RED,YELLOW,BLUE
}
воплощать в жизньjavac ColorEn.java
команда для создания файла ColorEn.class.
затем выполнитьjavap ColorEn.class
команда, вывод выглядит следующим образом:
Compiled from "ColorEn.java"
public final class io.github.dunwu.javacore.enumeration.ColorEn extends java.lang.Enum<io.github.dunwu.javacore.enumeration.ColorEn> {
public static final io.github.dunwu.javacore.enumeration.ColorEn RED;
public static final io.github.dunwu.javacore.enumeration.ColorEn YELLOW;
public static final io.github.dunwu.javacore.enumeration.ColorEn BLUE;
public static io.github.dunwu.javacore.enumeration.ColorEn[] values();
public static io.github.dunwu.javacore.enumeration.ColorEn valueOf(java.lang.String);
static {};
}
: лампочка: Описание:
Как видно из примера:
Суть перечисления в том,
java.lang.Enum
подкласс .несмотря на то что
enum
Похоже на новый тип данных, на самом деле,enum является ограниченным классом и имеет свои собственные методы. Перечисление является особым классом, потому что оно оформлено какfinal
, поэтому он не может наследоваться от других классов.Значение перечисления определено, значение по умолчанию будет изменено на
public static final
, из ключевого слова модификатора видно, что значение перечисления по существу является статической константой.
метод перечисления
В enum предоставляются некоторые основные методы:
-
values()
: возвращает массив экземпляров перечисления с элементами массива строго в том порядке, в котором они были объявлены в перечислении. -
name()
: возвращает имя экземпляра. -
ordinal()
: возвращает порядок, в котором экземпляр был объявлен, начиная с 0. -
getDeclaringClass()
: возвращает тип перечисления, к которому принадлежит экземпляр. -
equals()
: определить, является ли это одним и тем же объектом.
можно использовать==
сравниватьenum
пример.
также,java.lang.Enum
ДостигнутоComparable
иSerializable
интерфейс, поэтому также обеспечиваетcompareTo()
метод.
Пример: показать основной метод enum
public class EnumMethodDemo {
enum Color {RED, GREEN, BLUE;}
enum Size {BIG, MIDDLE, SMALL;}
public static void main(String args[]) {
System.out.println("=========== Print all Color ===========");
for (Color c : Color.values()) {
System.out.println(c + " ordinal: " + c.ordinal());
}
System.out.println("=========== Print all Size ===========");
for (Size s : Size.values()) {
System.out.println(s + " ordinal: " + s.ordinal());
}
Color green = Color.GREEN;
System.out.println("green name(): " + green.name());
System.out.println("green getDeclaringClass(): " + green.getDeclaringClass());
System.out.println("green hashCode(): " + green.hashCode());
System.out.println("green compareTo Color.GREEN: " + green.compareTo(Color.GREEN));
System.out.println("green equals Color.GREEN: " + green.equals(Color.GREEN));
System.out.println("green equals Size.MIDDLE: " + green.equals(Size.MIDDLE));
System.out.println("green equals 1: " + green.equals(1));
System.out.format("green == Color.BLUE: %b\n", green == Color.BLUE);
}
}
вывод
=========== Print all Color ===========
RED ordinal: 0
GREEN ordinal: 1
BLUE ordinal: 2
=========== Print all Size ===========
BIG ordinal: 0
MIDDLE ordinal: 1
SMALL ordinal: 2
green name(): GREEN
green getDeclaringClass(): class org.zp.javase.enumeration.EnumDemo$Color
green hashCode(): 460141958
green compareTo Color.GREEN: 0
green equals Color.GREEN: true
green equals Size.MIDDLE: false
green equals 1: false
green == Color.BLUE: false
перечисленные свойства
Характеристики перечисления можно суммировать в одном предложении:
Помимо невозможности наследовать, в основном вы можете
enum
как обычный класс.
Но это предложение нужно разделить, чтобы понять, давайте углубимся в детали.
Основные характеристики
Если в перечислении не определены методы, вы также можете добавить запятую, точку с запятой или ничего после последнего экземпляра.
Если в перечислении не определен метод,Значения перечисления по умолчанию равны порядковым номерам, начинающимся с 0.. Цвет в примере перечисляемого типа, который был константой перечисленияRED:0,GREEN:1,BLUE:2
.
Перечисления могут добавлять методы
Как упоминалось в главе о концепциях,Значения перечисления по умолчанию равны порядковым номерам, начинающимся с 0.. Итак, возникает вопрос: как явно присвоить значения перечислениям.
(1)Java не допускается=
Присвоить значения константам перечисления
Если вы знакомы с C/C++, вы, естественно, будете думать о символах присваивания.=
. В перечислении языка C/C++ вы можете использовать символ присваивания=
Явно присваивать значения константам перечисления, однако, к сожалению,Обозначение присваивания не разрешено в синтаксисе Java.=
Присвоить значения константам перечисления.
Пример: объявление перечисления на языке C/C++
typedef enum {
ONE = 1,
TWO,
THREE = 3,
TEN = 10
} Number;
(2)Перечисление может добавлять обычные методы, статические методы, абстрактные методы и конструкторы.
Хотя Java не может напрямую присваивать значения экземплярам, у нее есть лучшее решение:Добавьте методы в перечисление, чтобы косвенно реализовать явное назначение.
Создайтеenum
, вы можете добавить к нему несколько методов и даже добавить к нему конструкторы.
Обратите внимание на одну деталь: если вы хотите определить метод для перечисления, вы должны добавить точку с запятой в конце последнего экземпляра перечисления. Кроме того, в перечислении экземпляр должен быть определен первым, а поля или методы не могут быть определены до экземпляра. В противном случае компилятор сообщит об ошибке.
Пример: всесторонне покажите, как определять общие методы, статические методы, абстрактные методы и конструкторы в перечислении.
public enum ErrorCodeEn {
OK(0) {
@Override
public String getDescription() {
return "成功";
}
},
ERROR_A(100) {
@Override
public String getDescription() {
return "错误A";
}
},
ERROR_B(200) {
@Override
public String getDescription() {
return "错误B";
}
};
private int code;
// 构造方法:enum的构造方法只能被声明为private权限或不声明权限
private ErrorCodeEn(int number) { // 构造方法
this.code = number;
}
public int getCode() { // 普通方法
return code;
} // 普通方法
public abstract String getDescription(); // 抽象方法
public static void main(String args[]) { // 静态方法
for (ErrorCodeEn s : ErrorCodeEn.values()) {
System.out.println("code: " + s.getCode() + ", description: " + s.getDescription());
}
}
}
// Output:
// code: 0, description: 成功
// code: 100, description: 错误A
// code: 200, description: 错误B
Примечание. Приведенный выше пример нежелателен, он просто показывает, что enum поддерживает определение различных методов. правильный пример ситуацииПример кода ошибки
Enums может реализовывать интерфейсы
enum
Интерфейсы могут быть реализованы так же, как обычные классы.
Он также реализует класс перечисления кодов ошибок из предыдущего раздела.Реализуя интерфейс, вы можете ограничить его методы.
public interface INumberEnum {
int getCode();
String getDescription();
}
public enum ErrorCodeEn2 implements INumberEnum {
OK(0, "成功"),
ERROR_A(100, "错误A"),
ERROR_B(200, "错误B");
ErrorCodeEn2(int number, String description) {
this.code = number;
this.description = description;
}
private int code;
private String description;
@Override
public int getCode() {
return code;
}
@Override
public String getDescription() {
return description;
}
}
Перечисления не могут быть унаследованы
Перечисление не может наследовать другой класс и, конечно же, не может наследовать другое перечисление.
так какenum
на самом деле унаследовано отjava.lang.Enum
class, а Java не поддерживает множественное наследование, поэтомуenum
Не может наследовать другой класс и уж точно не может наследовать другойenum
.
перечисленные приложения
Постоянная организация
До JDK5 определение констант в Java былоpublic static final TYPE a;
такая форма. С помощью перечислений вы можете организовать связанные константы, чтобы сделать ваш код более читабельным и безопасным, а также использовать методы, предоставляемые перечислениями.
Следующие три объявления эквивалентны:
enum Color { RED, GREEN, BLUE }
enum Color { RED, GREEN, BLUE, }
enum Color { RED, GREEN, BLUE; }
автомат переключения состояний
Мы часто используем операторы switch для написания конечных автоматов. После JDK7 коммутатор поддерживаетсяint
,char
,String
,enum
тип параметра. По сравнению с этими типами параметров код переключения с использованием перечислений более читабелен.
public class StateMachineDemo {
public enum Signal {
GREEN, YELLOW, RED
}
public static String getTrafficInstruct(Signal signal) {
String instruct = "信号灯故障";
switch (signal) {
case RED:
instruct = "红灯停";
break;
case YELLOW:
instruct = "黄灯请注意";
break;
case GREEN:
instruct = "绿灯行";
break;
default:
break;
}
return instruct;
}
public static void main(String[] args) {
System.out.println(getTrafficInstruct(Signal.RED));
}
}
// Output:
// 红灯停
код ошибки
Перечисления часто используются для определения кодов ошибок программы. Вот простой пример:
public class ErrorCodeEnumDemo {
enum ErrorCodeEn {
OK(0, "成功"),
ERROR_A(100, "错误A"),
ERROR_B(200, "错误B");
ErrorCodeEn(int number, String msg) {
this.code = number;
this.msg = msg;
}
private int code;
private String msg;
public int getCode() {
return code;
}
public String getMsg() {
return msg;
}
@Override
public String toString() {
return "ErrorCodeEn{" + "code=" + code + ", msg='" + msg + '\'' + '}';
}
public static String toStringAll() {
StringBuilder sb = new StringBuilder();
sb.append("ErrorCodeEn All Elements: [");
for (ErrorCodeEn code : ErrorCodeEn.values()) {
sb.append(code.getCode()).append(", ");
}
sb.append("]");
return sb.toString();
}
}
public static void main(String[] args) {
System.out.println(ErrorCodeEn.toStringAll());
for (ErrorCodeEn s : ErrorCodeEn.values()) {
System.out.println(s);
}
}
}
// Output:
// ErrorCodeEn All Elements: [0, 100, 200, ]
// ErrorCodeEn{code=0, msg='成功'}
// ErrorCodeEn{code=100, msg='错误A'}
// ErrorCodeEn{code=200, msg='错误B'}
Перечень организаций
Перечисления подобных типов могут быть организованы по интерфейсам или классам, но обычно они организованы по интерфейсам.
Причина в том, что интерфейсы Java автоматически добавляются к типу enum во время компиляции.public static
модификатор; классы Java автоматически компилируются какenum
Введите с модификатором static. Увидеть разницу? Правильно, то есть организованы в классыenum
, если вы не измените его какpublic
, то к нему можно получить доступ только внутри этого пакета.
Пример: Организация перечисления в интерфейсе
public class EnumInInterfaceDemo {
public interface INumberEnum {
int getCode();
String getDescription();
}
public interface Plant {
enum Vegetable implements INumberEnum {
POTATO(0, "土豆"),
TOMATO(0, "西红柿");
Vegetable(int number, String description) {
this.code = number;
this.description = description;
}
private int code;
private String description;
@Override
public int getCode() {
return this.code;
}
@Override
public String getDescription() {
return this.description;
}
}
enum Fruit implements INumberEnum {
APPLE(0, "苹果"),
ORANGE(0, "桔子"),
BANANA(0, "香蕉");
Fruit(int number, String description) {
this.code = number;
this.description = description;
}
private int code;
private String description;
@Override
public int getCode() {
return this.code;
}
@Override
public String getDescription() {
return this.description;
}
}
}
public static void main(String[] args) {
for (Plant.Fruit f : Plant.Fruit.values()) {
System.out.println(f.getDescription());
}
}
}
// Output:
// 苹果
// 桔子
// 香蕉
Пример: Организация перечислений в классах
Этот пример аналогичен предыдущему эффекту.
public class EnumInClassDemo {
public interface INumberEnum {
int getCode();
String getDescription();
}
public static class Plant2 {
enum Vegetable implements INumberEnum {
// 略,与上面完全相同
}
enum Fruit implements INumberEnum {
// 略,与上面完全相同
}
}
// 略
}
// Output:
// 土豆
// 西红柿
Перечисление политик
Перечисление стратегий показано в Effective Java. Это перечисление классифицирует константы перечисления путем перечисления вложенных перечислений.
Хотя этот подход не такой лаконичный, как оператор switch, он более безопасный и гибкий.
Пример: Пример перечисления стратегии в EffectvieJava
enum PayrollDay {
MONDAY(PayType.WEEKDAY), TUESDAY(PayType.WEEKDAY), WEDNESDAY(
PayType.WEEKDAY), THURSDAY(PayType.WEEKDAY), FRIDAY(PayType.WEEKDAY), SATURDAY(
PayType.WEEKEND), SUNDAY(PayType.WEEKEND);
private final PayType payType;
PayrollDay(PayType payType) {
this.payType = payType;
}
double pay(double hoursWorked, double payRate) {
return payType.pay(hoursWorked, payRate);
}
// 策略枚举
private enum PayType {
WEEKDAY {
double overtimePay(double hours, double payRate) {
return hours <= HOURS_PER_SHIFT ? 0 : (hours - HOURS_PER_SHIFT)
* payRate / 2;
}
},
WEEKEND {
double overtimePay(double hours, double payRate) {
return hours * payRate / 2;
}
};
private static final int HOURS_PER_SHIFT = 8;
abstract double overtimePay(double hrs, double payRate);
double pay(double hoursWorked, double payRate) {
double basePay = hoursWorked * payRate;
return basePay + overtimePay(hoursWorked, payRate);
}
}
}
контрольная работа
System.out.println("时薪100的人在周五工作8小时的收入:" + PayrollDay.FRIDAY.pay(8.0, 100));
System.out.println("时薪100的人在周六工作8小时的收入:" + PayrollDay.SATURDAY.pay(8.0, 100));
Перечисление реализует шаблон singleton
Одноэлементный шаблон является наиболее часто используемым шаблоном проектирования.
Одноэлементный шаблон имеет проблемы с безопасностью потоков в параллельной среде.
Что касается вопросов безопасности потоков, традиционные методы таковы:
- Голодная китайская загрузка
- Ленивая синхронизация и двойная проверка
- Используйте механизм статической загрузки Java
По сравнению с вышеописанным методом синглтон тоже можно реализовать с помощью перечисления, и он тоже проще:
public class SingleEnumDemo {
public enum SingleEn {
INSTANCE;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public static void main(String[] args) {
SingleEn.INSTANCE.setName("zp");
System.out.println(SingleEn.INSTANCE.getName());
}
}
Дальнейшее чтение:Глубокое понимание типов перечисления Java (enum)
В этой статье очень внимательно рассматриваются характеристики перечисления Java, особенно реализация одноэлементного и традиционного одноэлементного перечисления.
класс инструмента перечисления
Java предоставляет два класса инструментов для простого управления перечислением:EnumSet
иEnumMap
.
EnumSet
EnumSet
это высокая производительность типов EnumSet
выполнить. Он требует, чтобы константы перечисления, помещаемые в него, были одного и того же типа перечисления.
Основной интерфейс:
-
noneOf
- Создает пустой EnumSet с указанным типом элемента -
allOf
- Создает EnumSet указанного типа элемента и содержит все значения перечисления -
range
- Создает EnumSet, который включает элементы указанного диапазона значений перечисления. -
complementOf
- Начальный набор включает дополнение указанного набора -
of
- Создайте EnumSet, который включает все элементы в параметре -
copyOf
- Создает EnumSet, содержащий все элементы в контейнере параметров
Пример:
public class EnumSetDemo {
public static void main(String[] args) {
System.out.println("EnumSet展示");
EnumSet<ErrorCodeEn> errSet = EnumSet.allOf(ErrorCodeEn.class);
for (ErrorCodeEn e : errSet) {
System.out.println(e.name() + " : " + e.ordinal());
}
}
}
EnumMap
EnumMap
специально адаптирован для типов перечисленияMap
выполнить. Хотя другие реализации Map (такие как HashMap) также могут выполнять сопоставление экземпляра типа перечисления со значением, использование EnumMap более эффективно: он может получать только экземпляры того же типа перечисления, что и ключевые значения, и из-за количества экземпляров типа перечисления. и ограниченный, EnumMap использует массив для хранения значений, соответствующих типу перечисления. Это делает EnumMap очень эффективным.
Основной интерфейс:
-
size
- возвращает количество пар ключ-значение -
containsValue
- существует ли указанное значение -
containsKey
- существует ли указанный ключ -
get
- Получить значение по указанному ключу -
put
- Получить указанную пару ключ-значение -
remove
- удалить указанный ключ -
putAll
- Вынимать пары ключ-значение в пакетах -
clear
- очистить данные -
keySet
- получить набор ключей -
values
- вернуться ко всем
Пример:
public class EnumMapDemo {
public enum Signal {
GREEN, YELLOW, RED
}
public static void main(String[] args) {
System.out.println("EnumMap展示");
EnumMap<Signal, String> errMap = new EnumMap(Signal.class);
errMap.put(Signal.RED, "红灯");
errMap.put(Signal.YELLOW, "黄灯");
errMap.put(Signal.GREEN, "绿灯");
for (Iterator<Map.Entry<Signal, String>> iter = errMap.entrySet().iterator(); iter.hasNext();) {
Map.Entry<Signal, String> entry = iter.next();
System.out.println(entry.getKey().name() + " : " + entry.getValue());
}
}
}
Дальнейшее чтение:Глубокое понимание типов перечисления Java (enum)
В этой статье дается более подробное введение в принципы EnumSet и EnumMap.