предисловие
С приближением Праздника Весны я желаю всем счастливого Нового года. Я разобрался с соответствующими знаниями в области нумерации Java, которая является относительно базовой, и я надеюсь, что все смогут учиться и прогрессировать вместе.
1. Что такое тип перечисления?
JDK5 представил новую функцию, ключевое слово enum может создать новый тип из ограниченного набора именованных значений, и эти именованные значения можно использовать в качестве обычных компонентов программы, что является типом перечисления.
Простой пример перечисления
enum SeasonEnum {
SPRING,SUMMER,FALL,WINTER;
}
Во-вторых, общий метод класса перечисления
Общие методы Enum следующие:
- name(); Возвращает имя экземпляра перечисления при его объявлении.
- ordinal(); Возвращает значение int, представляющее порядок, в котором объявляются экземпляры перечисления.
- equals(); возвращает логическое значение, экземпляр перечисления оценивается как равный
- compareTo() сравнивает порядок экземпляра перечисления с указанным объектом
- values(); возвращает массив экземпляров перечисления
- valueOf(String name) Получить константу, определенную в классе перечисления, по имени
Просто посмотрите на пример:
enum Shrubbery {
GROUND,CRAWLING, HANGING
}
public class EnumClassTest {
public static void main(String[] args) {
//values 返回enum实例的数组
for (Shrubbery temp : Shrubbery.values()) {
// name 返回实例enum声明的名字
System.out.println(temp.name() + " ordinal is " + temp.ordinal() + " ,equal result is " +
Shrubbery.CRAWLING.equals(temp) + ",compare result is " + Shrubbery.CRAWLING.compareTo(temp));
}
//由名称获取枚举类中定义的常量值
System.out.println(Shrubbery.valueOf("CRAWLING"));
}
}
результат операции:
GROUND ordinal is 0 ,equal result is false,compare result is 1
CRAWLING ordinal is 1 ,equal result is true,compare result is 0
HANGING ordinal is 2 ,equal result is false,compare result is -1
CRAWLING
В-третьих, истинное лицо класса перечисления
Что такое тип перечисления? Давайте создадим простой пример перечисления и посмотрим на его истинное лицо. следующим образом:
public enum Shrubbery {
GROUND,CRAWLING, HANGING
}
Используйте javac для компиляции приведенного выше класса перечисления, чтобы получить файл Shrubbery.class.
javac Shrubbery.java
Затем используйте команду javap для декомпиляции, чтобы получить файл байт-кода. например: выполнитьjavap Shrubbery.class
Доступны следующие файлы байт-кода.
Compiled from "Shrubbery.java"
public final class enumtest.Shrubbery extends java.lang.Enum<enumtest.Shrubbery> {
public static final enumtest.Shrubbery GROUND;
public static final enumtest.Shrubbery CRAWLING;
public static final enumtest.Shrubbery HANGING;
public static enumtest.Shrubbery[] values();
public static enumtest.Shrubbery valueOf(java.lang.String);
static {};
}
Из файла байт-кода его можно найти:
- Перечисление кустарников становится конечным классом, то есть не может быть унаследовано.
- Shrubbery является подклассом java.lang.Enum.
- Все значения перечисления, определенные Shrubbery, модифицируются с помощью public static final, то есть все они являются статическими константами.
Чтобы посмотреть подробнее, декомпилируйте javap с несколькими параметрами -c и выполните следующую команду:
javap -c Shrubbery.class
Файл байт-кода блока статического кода выглядит следующим образом:
static {};
Code:
0: new #4 // class enumtest/Shrubbery
3: dup
4: ldc #7 // String GROUND
6: iconst_0
7: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
10: putstatic #9 // Field GROUND:Lenumtest/Shrubbery;
13: new #4 // class enumtest/Shrubbery
16: dup
17: ldc #10 // String CRAWLING
19: iconst_1
20: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
23: putstatic #11 // Field CRAWLING:Lenumtest/Shrubbery;
26: new #4 // class enumtest/Shrubbery
29: dup
30: ldc #12 // String HANGING
32: iconst_2
33: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
36: putstatic #13 // Field HANGING:Lenumtest/Shrubbery;
39: iconst_3
40: anewarray #4 // class enumtest/Shrubbery
43: dup
44: iconst_0
45: getstatic #9 // Field GROUND:Lenumtest/Shrubbery;
48: aastore
49: dup
50: iconst_1
51: getstatic #11 // Field CRAWLING:Lenumtest/Shrubbery;
54: aastore
55: dup
56: iconst_2
57: getstatic #13 // Field HANGING:Lenumtest/Shrubbery;
60: aastore
61: putstatic #1 // Field $VALUES:[Lenumtest/Shrubbery;
64: return
}
- Строки 0-39 создают экземпляры GROUND, CRAWLING, HANGING класса перечисления Shrubbery;
- 40-64 — это операция создания массива Shrubbery[] $VALUES и размещения в массиве трех указанных выше экземпляров объектов.
- Таким образом, понятно, что метод values() класса перечисления возвращает массив экземпляров перечисления.
В-четвертых, преимущества классов перечисления
Каковы преимущества классов перечисления? Вот почему мы решили использовать классы enum? потому что это усиливаетЧитабельность кода, ремонтопригодность, а также имеетБезопасностьсекс.
Классы перечисления могут улучшить читаемость и удобство сопровождения.
Допустим, сейчас такой бизнес-сценарий: После того, как заказ выполнен, покупатель уведомляется о комментарии. Легко иметь следующий код:
//订单已完成
if(3==orderStatus){
//do something
}
Очевидно, что в этом коде есть магическое число.Если вы не напишите комментарий, кто знает, что представляет собой статус 3 для заказа.Это не только трудно читать, но и очень больно поддерживать? При использованииперечисляемый классНу, следующим образом:
public enum OrderStatusEnum {
UNPAID(0, "未付款"), PAID(1, "已付款"), SEND(2, "已发货"), FINISH(3, "已完成"),;
private int index;
private String desc;
public int getIndex() {
return index;
}
public String getDesc() {
return desc;
}
OrderStatusEnum(int index, String desc) {
this.index = index;
this.desc = desc;
}
}
//订单已完成
if(OrderStatusEnum.FINISH.getIndex()==orderStatus){
//do something
}
Видно, что класс перечисления делает этот код более читабельным и простым в обслуживании.После добавления нового состояния заказа можно напрямую добавить еще одно состояние перечисления. Некоторые друзья думают, чтоpublic static final int
Эта статическая константа также может выполнять эту функцию следующим образом:
public class OrderStatus {
//未付款
public static final int UNPAID = 0;
public static final int PAID = 1;
public static final int SENDED = 2;
public static final int FINISH = 3;
}
//订单已完成
if(OrderStatus.FINISH==orderStatus){
//do something
}
Конечно, так реализованы статические константы, и проблем с читабельностью нет, и понятно писать код таким образом в повседневной работе. Однако определение переменных с одним и тем же значением int легко спутать, поскольку вы определяетеPAID
а такжеSENDED
Статус равен 2, и компилятор не сообщит об ошибке.
Следовательно, первое преимущество классов перечисления состоит в том, чтоЧитабельность и ремонтопригодность хорошие, поэтому рекомендуется.
безопасность класса enum
Помимо удобочитаемости и удобства сопровождения, классы enum имеют огромное преимущество — безопасность.
Из анализа байт-кода класса перечисления в предыдущем разделе мы знаем, что:
- Класс перечисления модифицируется ключевым словом final и не может быть унаследован.
- И все его переменные являются общедоступными статическими окончательными изменениями, все статические переменные.
Статические ресурсы инициализируются, когда класс Java фактически используется в первый раз, а процесс загрузки и инициализации класса Java является потокобезопасным.
5. Обычное использование перечисления
константы организации enum
До JDK5 определение констант было таким: сначала определите класс или интерфейс, а типы свойств — public static final.... После перечисления вы можете организовать константы в классы перечисления следующим образом:
enum SeasonEnum {
SPRING,SUMMER,FALL,WINTER,;
}
Перечисление и переключатель взаимосвязаны
Как правило, в switch-case можно использовать только целочисленные значения, но экземпляры перечисления по своей сути находятся в порядке целочисленных значений, поэтому перечисления можно использовать в операторах switch следующим образом:
enum OrderStatusEnum {
UNPAID, PAID, SEND, FINISH
}
public class OrderStatusTest {
public static void main(String[] args) {
changeByOrderStatus(OrderStatusEnum.FINISH);
}
static void changeByOrderStatus(OrderStatusEnum orderStatusEnum) {
switch (orderStatusEnum) {
case UNPAID:
System.out.println("老板,你下单了,赶紧付钱吧");
break;
case PAID:
System.out.println("我已经付钱啦");
break;
case SENDED:
System.out.println("已发货");
break;
case FINISH:
System.out.println("订单完成啦");
break;
}
}
}
В повседневной разработке использование enum с переключателем сделает ваш код более читабельным.
Добавить новый метод в перечисление
В класс перечисления можно добавлять новые методы, такие как методы get, обычные методы и т. д. Наиболее часто в повседневной работе используется следующий метод написания перечисления:
public enum OrderStatusEnum {
UNPAID(0, "未付款"), PAID(1, "已付款"), SENDED(2, "已发货"), FINISH(3, "已完成"),;
//成员变量
private int index;
private String desc;
//get方法
public int getIndex() {
return index;
}
public String getDesc() {
return desc;
}
//构造器方法
OrderStatusEnum(int index, String desc) {
this.index = index;
this.desc = desc;
}
//普通方法
public static OrderStatusEnum of(int index){
for (OrderStatusEnum temp : values()) {
if (temp.getIndex() == index) {
return temp;
}
}
return null;
}
}
Перечисление реализует интерфейс
Все классы перечислений наследуются от java.lang.Enum, поэтому перечисления не могут наследоваться от других классов. Но перечисления могут реализовывать интерфейсы, что добавляет много красок перечислениям. следующим образом:
public interface ISeasonBehaviour {
void showSeasonBeauty();
String getSeasonName();
}
public enum SeasonEnum implements ISeasonBehaviour {
SPRING(1,"春天"),SUMMER(2,"夏天"),FALL(3,"秋天"),WINTER(4,"冬天"),
;
private int index;
private String name;
SeasonEnum(int index, String name) {
this.index = index;
this.name = name;
}
public int getIndex() {
return index;
}
public String getName() {
return name;
}
//接口方法
@Override
public void showSeasonBeauty() {
System.out.println("welcome to " + this.name);
}
//接口方法
@Override
public String getSeasonName() {
return this.name;
}
}
Используйте интерфейсы для организации перечислений
public interface Food {
enum Coffee implements Food{
BLACK_COFFEE,DECAF_COFFEE,LATTE,CAPPUCCINO
}
enum Dessert implements Food{
FRUIT, CAKE, GELATO
}
}
6. Используется ли == или equals для сравнения классов перечисления?
Давайте рассмотрим пример следующим образом:
public class EnumTest {
public static void main(String[] args) {
Shrubbery s1 = Shrubbery.CRAWLING;
Shrubbery s2 = Shrubbery.GROUND;
Shrubbery s3 = Shrubbery.CRAWLING;
System.out.println("s1==s2,result: " + (s1 == s2));
System.out.println("s1==s3,result: " + (s1 == s3));
System.out.println("Shrubbery.CRAWLING.equals(s1),result: "+Shrubbery.CRAWLING.equals(s1));
System.out.println("Shrubbery.CRAWLING.equals(s2),result: "+Shrubbery.CRAWLING.equals(s2));
}
}
результат операции:
s1==s2,result: false
s1==s3,result: true
Shrubbery.CRAWLING.equals(s1),result: true
Shrubbery.CRAWLING.equals(s2),result: false
Можно обнаружить, что можно использовать == или equals. На самом деле, метод equals перечисления использует == для сравнения, как показано ниже:
public final boolean equals(Object other) {
return this==other;
}
Seven, синглтон реализации перечисления
упомянутая эффективная Java,Лучший шаблон реализации синглтона — это шаблон перечисления.. Существует несколько способов реализации одноэлементного шаблона.Почему реализация перечисления является лучшим способом?
Поскольку синглтон, реализованный перечислением, имеет следующие преимущества:
- Написание одноэлементного перечисления просто
- Перечисления решают проблемы безопасности потоков
- Перечисления решают проблему десериализации, нарушающей синглтоны
Демонстрация одноэлементного перечисления выглядит следующим образом:
public class SingletonEnumTest {
public enum SingletonEnum {
INSTANCE,;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public static void main(String[] args) {
SingletonEnum.INSTANCE.setName("jay@huaxiao");
System.out.println(SingletonEnum.INSTANCE.getName());
}
}
Что касается реализации одноэлементного перечисления, друзья, которые хотят узнать больше, могут прочитать эту статью Холлиса, которая действительно хорошо написана!Почему я рекомендую вам использовать перечисления для реализации синглетонов.
Восемь, EnumSet и EnumMap
EnumSet
Давайте посмотрим на схему системы наследования EnumSet.
Очевидно, что EnumSet также реализует интерфейс set и по сравнению с HashSet имеет следующие преимущества:
- потреблять меньше памяти
- Он более эффективен, поскольку реализован в виде битового вектора.
- Предсказуемый порядок обхода (порядок объявления констант перечисления)
- отказаться от добавления нуля
EnumSet — это высокопроизводительная реализация набора, и его требование состоит в том, что хранилище должно относиться к тому же типу перечисления.Общие методы EnumSet:
- allof() создает EnumSet, который содержит все значения перечисления в указанном классе перечисления.
- range() получает экземпляр перечисления диапазона
- of() создает EnumSet, который включает в себя все элементы перечисления в параметре
- complementOf() Исходный нумерованный набор включает в себя дополнение к указанному нумерованному набору.
Посмотрите на пример, самый практичный:
public class EnumTest {
public static void main(String[] args) {
// Creating a set
EnumSet<SeasonEnum> set1, set2, set3, set4;
// Adding elements
set1 = EnumSet.of(SeasonEnum.SPRING, SeasonEnum.FALL, SeasonEnum.WINTER);
set2 = EnumSet.complementOf(set1);
set3 = EnumSet.allOf(SeasonEnum.class);
set4 = EnumSet.range(SeasonEnum.SUMMER,SeasonEnum.WINTER);
System.out.println("Set 1: " + set1);
System.out.println("Set 2: " + set2);
System.out.println("Set 3: " + set3);
System.out.println("Set 4: " + set4);
}
}
Выходной результат:
Set 1: [SPRING, FALL, WINTER]
Set 2: [SUMMER]
Set 3: [SPRING, SUMMER, FALL, WINTER]
Set 4: [SUMMER, FALL, WINTER]
EnumMap
Схема системы наследования EnumMap выглядит следующим образом:
EnumMap также реализует интерфейс Map и по сравнению с HashMap имеет следующие преимущества:
- потреблять меньше памяти
- более высокая эффективность
- Предсказуемый порядок обхода
- отклонить ноль
EnumMap — это высокопроизводительная реализация карты.Его общий метод совместим с HashMap, единственное ограничение связано с перечислением.
Посмотрите на пример, самый практичный:
public class EnumTest {
public static void main(String[] args) {
Map<SeasonEnum, String> map = new EnumMap<>(SeasonEnum.class);
map.put(SeasonEnum.SPRING, "春天");
map.put(SeasonEnum.SUMMER, "夏天");
map.put(SeasonEnum.FALL, "秋天");
map.put(SeasonEnum.WINTER, "冬天");
System.out.println(map);
System.out.println(map.get(SeasonEnum.SPRING));
}
}
результат операции
{SPRING=春天, SUMMER=夏天, FALL=秋天, WINTER=冬天}
春天
9. Будет обновлено
Есть ключевые моменты знаний о перечислении, дорогой друг, есть что добавить?
Ссылка и спасибо
- Углубленный анализ перечисления Enum в Java
- Углубленный анализ типа перечисления Java — безопасность потоков и сериализация перечисления.
- Почему я рекомендую вам использовать перечисления для реализации синглетонов.
- Глубокое понимание типов перечисления Java (enum)
- Глубокое понимание перечислений в Java.
- EnumSet in Java
- Перечисление Java (enum) подробно объясняет 7 распространенных способов использования
- «Идеи программирования на Java»
Личный публичный аккаунт
- Если вы хороший ребенок, который любит учиться, вы можете подписаться на мой официальный аккаунт, чтобы вместе учиться и обсуждать.
- Если вы считаете, что в этой статье есть какие-либо неточности, вы можете прокомментировать или подписаться на мой официальный аккаунт, пообщаться со мной в частном порядке, и все смогут учиться и прогрессировать вместе.