Освоения этих знаний перечисления Java достаточно для ежедневной разработки

Java

предисловие

С приближением Праздника Весны я желаю всем счастливого Нового года. Я разобрался с соответствующими знаниями в области нумерации Java, которая является относительно базовой, и я надеюсь, что все смогут учиться и прогрессировать вместе.

Все демонстрации кода в этой главе загружены на github.

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. Будет обновлено

Есть ключевые моменты знаний о перечислении, дорогой друг, есть что добавить?

Ссылка и спасибо

Личный публичный аккаунт

  • Если вы хороший ребенок, который любит учиться, вы можете подписаться на мой официальный аккаунт, чтобы вместе учиться и обсуждать.
  • Если вы считаете, что в этой статье есть какие-либо неточности, вы можете прокомментировать или подписаться на мой официальный аккаунт, пообщаться со мной в частном порядке, и все смогут учиться и прогрессировать вместе.