Перечисление — это новый тип данных в JDK 1.5. Используя перечисление, мы можем хорошо описать некоторые конкретные бизнес-сценарии, такие как весна, лето, осень, зима в году и каждую неделю с понедельника по воскресенье. использоваться для описания некоторой информации о состоянии, такой как коды ошибок и т. д.
Типы-перечисления существуют не только в языке Java, но также могут быть найдены в других языках, таких как C# и Python, но я обнаружил, что мало кто использует перечисления в реальных проектах, поэтому я расскажу об этом в этой статье. связанное содержание перечисления, чтобы у друзей могло сложиться общее впечатление о перечислении, чтобы при программировании можно было подумать хотя бы об одном типе «перечисления».
Структура каталога этой статьи выглядит следующим образом:
7 способов использования перечислений
Важная причина, по которой многие люди не используют перечисления, заключается в том, что они недостаточно знакомы с перечислениями, поэтому давайте начнем с 7 способов использования перечислений.
Использование 1: константы
До JDK 1.5 мы определяли константы какpublic static final..., но с перечислением мы можем определить эти константы как класс перечисления, код реализации выглядит следующим образом:
public enum ColorEnum {
RED, GREEN, BLANK, YELLOW
}
Использование 2: переключатель
Использование перечисления в оценке переключения делает код более читабельным Код реализации выглядит следующим образом:
enum ColorEnum {
GREEN, YELLOW, RED
}
public class ColorTest {
ColorEnum color = ColorEnum.RED;
public void change() {
switch (color) {
case RED:
color = ColorEnum.GREEN;
break;
case YELLOW:
color = ColorEnum.RED;
break;
case GREEN:
color = ColorEnum.YELLOW;
break;
}
}
}
Использование 3: добавление методов в перечисление
Мы можем добавить некоторые методы к перечислению, чтобы сделать перечисление более функциональным, Код реализации выглядит следующим образом:
public class EnumTest {
public static void main(String[] args) {
ErrorCodeEnum errorCode = ErrorCodeEnum.SUCCESS;
System.out.println("状态码:" + errorCode.code() +
" 状态信息:" + errorCode.msg());
}
}
enum ErrorCodeEnum {
SUCCESS(1000, "success"),
PARAM_ERROR(1001, "parameter error"),
SYS_ERROR(1003, "system error"),
NAMESPACE_NOT_FOUND(2001, "namespace not found"),
NODE_NOT_EXIST(3002, "node not exist"),
NODE_ALREADY_EXIST(3003, "node already exist"),
UNKNOWN_ERROR(9999, "unknown error");
private int code;
private String msg;
ErrorCodeEnum(int code, String msg) {
this.code = code;
this.msg = msg;
}
public int code() {
return code;
}
public String msg() {
return msg;
}
public static ErrorCodeEnum getErrorCode(int code) {
for (ErrorCodeEnum it : ErrorCodeEnum.values()) {
if (it.code() == code) {
return it;
}
}
return UNKNOWN_ERROR;
}
}
Результат выполнения вышеуказанной программы:
Код состояния: 1000 Информация о состоянии: успех
Использование 4: переопределить метод перечисления
Мы можем переопределить некоторые методы перечисления для реализации собственного бизнеса, например, мы можем переопределитьtoString()метод, код реализации выглядит следующим образом:
public class EnumTest {
public static void main(String[] args) {
ColorEnum colorEnum = ColorEnum.RED;
System.out.println(colorEnum.toString());
}
}
enum ColorEnum {
RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLOW("黄色", 4);
// 成员变量
private String name;
private int index;
// 构造方法
private ColorEnum(String name, int index) {
this.name = name;
this.index = index;
}
//覆盖方法
@Override
public String toString() {
return this.index + ":" + this.name;
}
}
Результат выполнения вышеуказанной программы:
1: красный
Использование 5: Реализация интерфейса
Классы перечисления можно использовать для реализации интерфейсов, но нельзя использовать для наследования классов, поскольку перечисления наследуются по умолчанию.java.lang.EnumКласс, который позволяет реализовать несколько интерфейсов на языке Java, но не может наследовать несколько родительских классов Код реализации выглядит следующим образом:
public class EnumTest {
public static void main(String[] args) {
ColorEnum colorEnum = ColorEnum.RED;
colorEnum.print();
System.out.println("颜色:" + colorEnum.getInfo());
}
}
interface Behaviour {
void print();
String getInfo();
}
enum ColorEnum implements Behaviour {
RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLOW("黄色", 4);
private String name;
private int index;
private ColorEnum(String name, int index) {
this.name = name;
this.index = index;
}
@Override
public void print() {
System.out.println(this.index + ":" + this.name);
}
@Override
public String getInfo() {
return this.name;
}
}
Результат выполнения вышеуказанной программы:
1: красный
красный цвет
Использование 6: Организация классов перечисления в интерфейсах
Мы можем создать несколько классов перечисления в интерфейсе, который можно использовать для достижения «полиморфизма», что означает, что мы можем объединять классы перечисления с одинаковыми характеристиками, но небольшими различиями в реализации в одном интерфейсе. Код реализации выглядит следующим образом:
public class EnumTest {
public static void main(String[] args) {
// 赋值第一个枚举类
ColorInterface colorEnum = ColorInterface.ColorEnum.RED;
System.out.println(colorEnum);
// 赋值第二个枚举类
colorEnum = ColorInterface.NewColorEnum.NEW_RED;
System.out.println(colorEnum);
}
}
interface ColorInterface {
enum ColorEnum implements ColorInterface {
GREEN, YELLOW, RED
}
enum NewColorEnum implements ColorInterface {
NEW_GREEN, NEW_YELLOW, NEW_RED
}
}
Результат выполнения вышеуказанной программы:
RED
NEW_RED
Использование 7: Использование перечисляемых коллекций
На языке Java, связанный с классом перечисления, есть также два класса коллекции перечисленияjava.util.EnumSetиjava.util.EnumMap, вы можете использовать их для достижения большего количества функций.
использоватьEnumSetОн может гарантировать, что элементы не повторяются, и может получить элементы в пределах указанного диапазона.Пример кода выглядит следующим образом:
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
public class EnumTest {
public static void main(String[] args) {
List<ColorEnum> list = new ArrayList<ColorEnum>();
list.add(ColorEnum.RED);
list.add(ColorEnum.RED); // 重复元素
list.add(ColorEnum.YELLOW);
list.add(ColorEnum.GREEN);
// 去掉重复数据
EnumSet<ColorEnum> enumSet = EnumSet.copyOf(list);
System.out.println("去重:" + enumSet);
// 获取指定范围的枚举(获取所有的失败状态)
EnumSet<ErrorCodeEnum> errorCodeEnums = EnumSet.range(ErrorCodeEnum.ERROR, ErrorCodeEnum.UNKNOWN_ERROR);
System.out.println("所有失败状态:" + errorCodeEnums);
}
}
enum ColorEnum {
RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLOW("黄色", 4);
private String name;
private int index;
private ColorEnum(String name, int index) {
this.name = name;
this.index = index;
}
}
enum ErrorCodeEnum {
SUCCESS(1000, "success"),
ERROR(2001, "parameter error"),
SYS_ERROR(2002, "system error"),
NAMESPACE_NOT_FOUND(2003, "namespace not found"),
NODE_NOT_EXIST(3002, "node not exist"),
NODE_ALREADY_EXIST(3003, "node already exist"),
UNKNOWN_ERROR(9999, "unknown error");
private int code;
private String msg;
ErrorCodeEnum(int code, String msg) {
this.code = code;
this.msg = msg;
}
public int code() {
return code;
}
public String msg() {
return msg;
}
}
Результат выполнения вышеуказанной программы:
Дедупликация: [КРАСНЫЙ, ЗЕЛЕНЫЙ, ЖЕЛТЫЙ]
Все состояния сбоя: [ERROR, SYS_ERROR, NAMESPACE_NOT_FOUND, NODE_NOT_EXIST, NODE_ALREADY_EXIST, UNKNOWN_ERROR]
EnumMapиHashMapАналогично, но это специальный дизайн для перечисленийMapсборник, по сравнению сHashMapС точки зрения производительности он имеет более высокую производительность, поскольку внутренне отказывается от использования связанных списков и красно-черных деревьев, а в качестве структур хранения данных использует массивы.
EnumMapБазовый пример использования выглядит следующим образом:
import java.util.EnumMap;
public class EnumTest {
public static void main(String[] args) {
EnumMap<ColorEnum, String> enumMap = new EnumMap<>(ColorEnum.class);
enumMap.put(ColorEnum.RED, "红色");
enumMap.put(ColorEnum.GREEN, "绿色");
enumMap.put(ColorEnum.BLANK, "白色");
enumMap.put(ColorEnum.YELLOW, "黄色");
System.out.println(ColorEnum.RED + ":" + enumMap.get(ColorEnum.RED));
}
}
enum ColorEnum {
RED, GREEN, BLANK, YELLOW;
}
Результат выполнения вышеуказанной программы:
Красный: красный
Меры предосторожности при использовании
В «Руководстве по разработке Java» Али есть следующие правила перечисления, при их использовании нам нужно уделить немного внимания.
[Обязательно] Все поля типа перечисления должны иметь комментарии, описывающие назначение каждого элемента данных.
[Ссылка] Имя класса перечисления должно иметь суффикс Enum, а имя члена перечисления должно быть все в верхнем регистре, а слова должны быть разделены символами подчеркивания. Примечание. Перечисления на самом деле являются специальными константными классами, и конструктор по умолчанию принудительно является закрытым. Положительный пример: имя перечисления Имя элемента ProcessStatusEnum: SUCCESS / UNKNOWN_REASON.
Без перечисления
До появления перечисления, то есть до версии JDK 1.5, мы обычно использовалиintКонстанты для представления перечисления, код реализации выглядит следующим образом:
public static final int COLOR_RED = 1;
public static final int COLOR_BLUE = 2;
public static final int COLOR_GREEN = 3;
Но используйтеintС типами может быть две проблемы:
Первый,intТипы небезопасны по своей сути, если программист определяетintна один раз меньшеfinalключевое слово, то есть риск быть измененным другими. С другой стороны, класс перечисления является "естественно" постоянным классом, и нет никакого риска быть измененным (см. вторую часть для причин);
Во-вторых, используйтеintСемантика этого типа недостаточно ясна, например, если при выводе на консоль мы выводим только такие числа, как 1...2...3, мы не должны знать, что это значит.
Потом кто-то сказал, тогда используйте символы-константы, это не значит, что вы не знаете семантики, верно? Пример кода реализации выглядит следующим образом:
public static final String COLOR_RED = "RED";
public static final String COLOR_BLUE = "BLUE";
public static final String COLOR_GREEN = "GREEN";
Но с этим тоже есть проблема.Некоторые младшие программисты не будут разыгрывать карты по рутине.Они могут напрямую использовать значение строки для сравнения вместо прямого использования поля перечисления.Код примера реализации выглядит следующим образом:
public class EnumTest {
public static final String COLOR_RED = "RED";
public static final String COLOR_BLUE = "BLUE";
public static final String COLOR_GREEN = "GREEN";
public static void main(String[] args) {
String color = "BLUE";
if ("BLUE".equals(color)) {
System.out.println("蓝色");
}
}
}
Таким образом, когда мы изменим значение в перечислении, программа будет крутой.
Перечисление сценариев использования
Распространенным вариантом использования перечисления является синглтон, и его полный код реализации выглядит следующим образом:
public class Singleton {
// 枚举类型是线程安全的,并且只会装载一次
private enum SingletonEnum {
INSTANCE;
// 声明单例对象
private final Singleton instance;
// 实例化
SingletonEnum() {
instance = new Singleton();
}
private Singleton getInstance() {
return instance;
}
}
// 获取实例(单例对象)
public static Singleton getInstance() {
return SingletonEnum.INSTANCE.getInstance();
}
private Singleton() {
}
// 类方法
public void sayHi() {
System.out.println("Hi,Java.");
}
}
class SingletonTest {
public static void main(String[] args) {
Singleton singleton = Singleton.getInstance();
singleton.sayHi();
}
}
Поскольку перечисление будет загружено только при загрузке класса, оно является потокобезопасным, что также является основной причиной, по которой автор "Effective Java" рекомендует использовать перечисления.
Расширение знаний
Почему перечисления потокобезопасны?
Давайте начнем с байт-кода, сгенерированного перечислением.Во-первых, давайте определим простой класс перечисления:
public enum ColorEnumTest {
RED, GREEN, BLANK, YELLOW;
}
Затем мы компилируем приведенный выше код как байт-код, конкретное содержание выглядит следующим образом:
public final class ColorEnumTest extends java.lang.Enum<ColorEnumTest> {
public static final ColorEnumTest RED;
public static final ColorEnumTest GREEN;
public static final ColorEnumTest BLANK;
public static final ColorEnumTest YELLOW;
public static ColorEnumTest[] values();
public static ColorEnumTest valueOf(java.lang.String);
static {};
}
Из приведенных выше результатов видно, что класс перечисления в конечном итоге будет скомпилирован, чтобы бытьfinalИзмененный обычный класс, все его свойства также будутstaticиfinalизменение ключевого слова, поэтому класс перечисления будет загружен и инициализирован JVM при запуске проекта, и этот процесс выполнения является потокобезопасным, поэтому класс перечисления также является потокобезопасным классом.
Советы. Процесс декомпиляции кода заключается в том, чтобы сначала использовать команду javac для компиляции кода Java в байт-код (.class), а затем использовать команду javap для просмотра скомпилированного байт-кода.
Советы по сравнению перечисления
Нам достаточно использовать == при сравнении перечислений, потому что класс перечисления создается при загрузке программы (это неnewout), а класс перечисления нельзя использовать напрямую извне.newключевое слово для создания экземпляра перечисления, поэтому у нас по сути есть только один объект при использовании класса перечисления, поэтому использования == при сравнении перечислений достаточно.
и мы смотрим на перечислениеequlas()Исходный код обнаружит, что на самом деле он напрямую вызывает внутренний метод == Исходный код выглядит следующим образом:
public final boolean equals(Object other) {
return this==other;
}
Суммировать
В этой статье мы представили 7 способов использования классов перечисления: константы, переключатель, добавление методов к перечислению, переопределение методов перечисления, реализация интерфейсов, организация классов перечисления в интерфейсах, использование коллекций перечисления и т. д. Используйте класс перечисления для использованияintтип иStringУ типов есть некоторые недостатки: семантика недостаточно ясна, ее легко изменить, и есть риск неправильного использования, поэтому мы должны попытаться использовать классы перечисления в подходящей среде. А еще мы поговорили о сценариях использования классов перечисления-синглетонов, и почему классы перечисления безопасны, и, наконец, мы поговорили о советах по сравнению перечислений, надеюсь, эта статья будет вам полезна.
Просмотр и благодарность
Woohoo.ITeye.com/blog/soft be…
Подпишитесь на официальный аккаунт «Java Chinese Community» и ответьте на «Галантные товары», чтобы получить 50 оригинальных галантерейных товаров.Топ-лист.