<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          語法糖甜不甜?巧用枚舉實現(xiàn)“狀態(tài)”轉換限制

          共 13569字,需瀏覽 28分鐘

           ·

          2021-10-02 00:17

          語法糖

          語法糖(Syntactic sugar),也被譯為糖衣語法,是由英國計算機科學家彼得·約翰·蘭達(Peter J. Landin)發(fā)明的一個術語,指計算機語言中添加的某種語法,這種語法對語言的功能并沒有影響,但是更方便程序員使用。通常來說使用語法糖能夠增加程序的可讀性,從而減少程序代碼出錯的機會。——摘抄自百度百科

          本質上,JVM 并不支持語法糖,語法糖只存在于編譯期。當編譯器將 .java 源文件編譯成 .class 字節(jié)碼文件時,會進行解語法糖的操作,來還原最原始的基礎語法結構。

          我們所熟悉的編程語言中幾乎都會包含語法糖,當然 JAVA 也不例外。JAVA 中的語法糖包含條件編譯斷言switch 支持 String 與枚舉可變參數(shù)自動裝箱/拆箱枚舉內部類泛型擦除增強for循環(huán)lambda表達式try-with-resources等等。今天我們先來了解下枚舉

           

          枚舉類

          JDK5 提供了一種新的特殊的類——枚舉類,一般在類對象有限且固定的場景下使用,用來替代類中定義常量的方式。枚舉相較于常量更加直觀且類型安全。

          枚舉類的使用非常簡單,用 enum 關鍵字來定義,多個枚舉變量直接用逗號隔開。我們先來定義一個簡單的枚舉類 OrderStatus.java

          public enum OrderStatus {
              //未支付、已支付、退款中、退款成功、退款失敗;
              NO_PAY, PAY, REFUNDING, REFUNDED, FAIL_REFUNDED, ;
          }

          在其他類中使用 enum 變量的時候,只需要【類名.變量名】就可以了,和使用靜態(tài)變量一樣。另外,枚舉類型可以確保 JVM 中僅存在一個常量實例,所以我們可以放心的使用“ ==”來比較兩個變量。

          注意事項:

          1. 枚舉類的第一行必須是枚舉項,最后一個枚舉項后的分號是可以省略的,但是如果枚舉類有其它的東西,這個分號就不能省略。建議不要省略!

          2. 枚舉變量最好大寫,多個單詞之間使用”_”隔開(比如:NO_PAY)。

          反編譯

          我們可以先通過 javac 命令或者 IDEA 的編譯功能將OrderStatus.java 編譯為OrderStatus.class 字節(jié)碼文件,然后用DJ Java Decompiler 反編譯器對 .class 文件進行反編譯。

          如果需要 DJ Java Decompiler 反編譯器的小伙伴可以私信阿Q獲取!

          public final class OrderStatus extends Enum
          {

              //該方法會返回包括所有枚舉變量的數(shù)組,可以方便的用來做循環(huán)。
              public static OrderStatus[] values()
              {
                  return (OrderStatus[])$VALUES.clone();
              }

              //根據(jù)傳入的字符串,轉變?yōu)閷拿杜e變量。
              //前提是傳的字符串和定義枚舉變量的字符串一抹一樣,區(qū)分大小寫。
              //如果傳了一個不存在的字符串,那么會拋出異常。
              public static OrderStatus valueOf(String name)
              
          {
                  return (OrderStatus)Enum.valueOf(com/itcast/java/enumpack/OrderStatus, name);
              }

              private OrderStatus(String s, int i)
              
          {
                  super(s, i);
              }

              public static final OrderStatus NO_PAY;
              public static final OrderStatus PAY;
              public static final OrderStatus REFUNDING;
              public static final OrderStatus REFUNDED;
              public static final OrderStatus FAIL_REFUNDED;
              private static final OrderStatus $VALUES[];

              static 
              {
                  NO_PAY = new OrderStatus("NO_PAY"0);
                  PAY = new OrderStatus("PAY"1);
                  REFUNDING = new OrderStatus("REFUNDING"2);
                  REFUNDED = new OrderStatus("REFUNDED"3);
                  FAIL_REFUNDED = new OrderStatus("FAIL_REFUNDED"4);
                  $VALUES = (new OrderStatus[] {
                      NO_PAY, PAY, REFUNDING, REFUNDED, FAIL_REFUNDED
                  });
              }
          }

          如源碼所示:

          • 編譯器會自動幫我們創(chuàng)建一個 final 類型的類繼承 Enum 類,所以枚舉類不能被繼承。

          • 會自動生成私有構造方法,當然我們也可以定義構造方法,但必須是私有的,這樣就不能在別處聲明此類的對象了。

          • 枚舉項會被自動添加 public static final 修飾,并定義為 OrderStatus 類型,并在靜態(tài)代碼塊中被初始化。

          • 并提供了 values()valueOf(String name) 的靜態(tài)方法。

          我們定義的枚舉變量實際上是編譯器幫我們自動生成了構造函數(shù)。

          所有枚舉類都是 Enum 的子類,枚舉類可以實現(xiàn)一個或多個接口。

          Enum

          Enum 是所有 Java 語言枚舉類型的公共基類,實現(xiàn)了 Comparable 和 Serializable 接口。它包含 final 類型的 name 和 ordinal (此枚舉常量的序號,從0開始)屬性,下面我們來了解下它的方法

          • protected Enum(String name, int ordinal);——構造方法;

          • public String toString();——返回 name 字段,即枚舉定義枚舉變量的字符串;

          • protected final Object clone();——拋出 CloneNotSupportedException 異常,保證枚舉類永遠不會被克隆;

          • public final ClassgetDeclaringClass();——返回與此枚舉常量的枚舉類型對應的類對象;

          • protected final void finalize();—— 枚舉類不能有 finalize 方法;

          • readObject(ObjectInputStream in);& readObjectNoData();—— 拋出InvalidObjectException 異常,防止默認反序列化;

          擴展

          1. 枚舉類中可以自定義屬性
            自定義的屬性值最好用 private final 修飾,防止生成的 set 方法在使用時修改屬性值,使代碼更加安全。
          2. 枚舉類中可以自定義構造函數(shù)
            構造函數(shù)必須為 private 修飾,防止在別處聲明此類對象。
          3. 枚舉類可以自定義方法,枚舉項可以選擇性覆蓋自定義的方法。

            public enum OrderStatus{
                NO_PAY("未支付",0),
                PAY("已支付",1){
                    @Override
                    public void printOrderStatus() {
                        System.out.println("已支付");
                    }
                },
                REFUNDING("退款中",2),
                REFUNDED("退款成功",3),
                FAIL_REFUNDED("退款失敗",4),
                ;

                private final String name;
                private final int status;

                private OrderStatus(String name,int status){
                    this.name = name;
                    this.status = status;
                }

                public void printOrderStatus(){
                    System.out.println("打印訂單狀態(tài)");
                }
            }


            public class EnumTest {
                public static void main(String[] args) {
                    OrderStatus.PAY.printOrderStatus();
                    OrderStatus.NO_PAY.printOrderStatus();
                }
            }

          枚舉類也可以有抽象方法,但是枚舉項必須重寫該方法。
          1. 枚舉類實現(xiàn)接口
            與普通類一樣,實現(xiàn)接口的時候需要實現(xiàn)接口的抽象方法,也可以讓枚舉類的不同對象實現(xiàn)不同的行為。

          //定義一個接口
          public interface Order {
              void printOrderStatus();
          }

          //枚舉類實現(xiàn)該接口
          public enum OrderStatus implements Order{
              NO_PAY("未支付",0){
                  @Override
                  public void printOrderStatus() {
                      System.out.println("未支付");
                  }
              },
              PAY("已支付",1){
                  @Override
                  public void printOrderStatus() {
                      System.out.println("已支付");
                  }
              },
              REFUNDING("退款中",2){
                  @Override
                  public void printOrderStatus() {
                      System.out.println("退款中");
                  }
              },
              REFUNDED("退款成功",3){
                  @Override
                  public void printOrderStatus() {
                      System.out.println("退款成功");
                  }
              },
              FAIL_REFUNDED("退款失敗",4){
                  @Override
                  public void printOrderStatus() {
                      System.out.println("退款失敗");
                  }
              },
              ;

              private final String name;
              private final int status;

              private OrderStatus(String name,int status){
                  this.name = name;
                  this.status = status;
              }
          }

          此時查看編譯后的文件,會發(fā)現(xiàn)除了生成 OrderStatus.class 文件之外,還生成了多個 .class 文件:
          它們是 OrderStatus.class 中生成的匿名內部類的文件。

           

          狀態(tài)轉換

          需求

          訂單是電商項目中不可缺少的組成部分,而訂單狀態(tài)的轉換也是我們經(jīng)常討論的問題。我們都知道訂單狀態(tài)的轉換是有一定的邏輯性的,不可以隨意轉換。
          :你想購買某個商品,只是把它加入了購物車,此時應該是未支付狀態(tài)。如果來個請求想把它轉換為退款狀態(tài),那么系統(tǒng)應該拋出提示信息“狀態(tài)轉換失敗,請先完成購買!”
          接下來我們就用枚舉來完成一下訂單狀態(tài)轉換的限制。

          實現(xiàn)

          枚舉類定義:

          public enum OrderStatus{
              NO_PAY("未支付",0){
                  @Override
                  public Boolean canChange(OrderStatus orderStatus) {
                      switch (orderStatus){
                          case PAY:
                              return true;
                          default:
                              return false;
                      }
                  }
              },
              PAY("已支付",1){
                  @Override
                  public Boolean canChange(OrderStatus orderStatus) {
                      //因為退款接口一般都會有延遲,所以會先轉化為“退款中”狀態(tài)
                      switch (orderStatus){
                          case REFUNDING:
                              return true;
                          default:
                              return false;
                      }
                  }
              },
              REFUNDING("退款中",2){
                  @Override
                  public Boolean canChange(OrderStatus orderStatus) {
                      switch (orderStatus){
                          case REFUNDED:
                          case FAIL_REFUNDED:
                              return true;
                          default:
                              return false;
                      }
                  }
              },
              REFUNDED("退款成功",3),
              FAIL_REFUNDED("退款失敗",4),
              ;

              private final String name;
              private final int status;

              private OrderStatus(String name,int status){
                  this.name = name;
                  this.status = status;
              }

              //自定義轉換方法
              public Boolean canChange(OrderStatus orderStatus){
                  return false;
              }
          }

          調用方法:

          public class EnumTest {

              public static void main(String[] args) {
                  Boolean aBoolean = OrderStatus.NO_PAY.canChange(OrderStatus.PAY);
                  String statusStr = aBoolean?"可以":"不可以";
                  System.out.println("是否可以完成狀態(tài)轉換:"+ statusStr);

                  Boolean flag = OrderStatus.REFUNDED.canChange(OrderStatus.FAIL_REFUNDED);
                  String flagStr = flag?"可以":"不可以";
                  System.out.println("是否可以完成狀態(tài)轉換:"+ flagStr);
              }
          }

          返回結果:
          這樣我們就用枚舉類實現(xiàn)了訂單狀態(tài)轉換的限制。此例子只是為狀態(tài)轉換提供一種思路,具體的流程還需要根據(jù)自己系統(tǒng)中的業(yè)務來具體處理。

          有道無術,術可成;有術無道,止于術

          歡迎大家關注Java之道公眾號


          好文章,我在看??

          瀏覽 43
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美精品aa | 91成人社区无码 | 天天搞天天射 | 国产精品高潮视频 | 午夜精品久久99热蜜桃剧情介绍 |