1. 程式人生 > >java枚舉細節

java枚舉細節

pareto 獲取 要去 ive 泛型 簡化 優點 真的 訂單

   1.在沒有枚舉之前,我們如果需要一些常量,比如說,我們想用一些常量來代替訂單的幾種狀態,如已下單未付款、已付款未發貨、已發貨未確認收貨、已收貨未評價、已評價。我們會定義一個用來裝常量的類,比如:

package com.xdx.learn;

public class OrderConstant {
    public static final int UNPAY=1;//未付款
    public static final int UNDELIVER=2;//未發貨
    public static final int UNRECEIVE=3;//未收貨
    public static
final int UNCOMMENT=4;//未評價 }

  在其他地方調用的時候,我們直接通過OrderConstant .UNPAY就可以獲取到這個常量。

  2.有了枚舉類型以後,我們會這樣來寫代碼。

  新建一個枚舉類。

  

public enum OrderEnum {
    UNPAY("unpay",1),UNDELIVER("undeliver",2),UNRECEIVE("unreceive",3),UNCOMMENT("uncomment",4);
    private String key;
    private int value;
    private
OrderEnum(String key,int value){ this.key=key; this.value=value; } public String getKey() { return key; } public void setKey(String key) { this.key = key; } public int getValue() { return value; } public void setValue(int
value) { this.value = value; } public static void main(String args[]){ System.out.println(OrderEnum.UNPAY.getKey()); System.out.println(OrderEnum.UNPAY.getValue()); } }

  上面就是一個枚舉類,它有如下特點。

  (1)它不用class修飾,而是用enum關鍵字來修飾。但是要知道的是,它本質上還是一個類。

  (2)它的構造函數不能用public修飾,只能用private來修飾,也就是說,我們不能在外部實例化一個枚舉類的對象。這讓你想到了什麽呢?是不是單例模式。

  (3)UNPAY("unpay",1),UNDELIVER("undeliver",2),UNRECEIVE("unreceive",3),UNCOMMENT("uncomment",4);這幾個都是該枚舉類的對象(他們都是OrderEnum類型的),以靜態常量的成員變量的形式存在於枚舉類中。事實上,他們是public static final類型的,所以我們可以在類外部使用類名.成員變量,比如OrderEnum.UNPAY的形式來訪問。

  (4)一旦你定義了一個枚舉類,則必須也將它的實例創建出來,即是上述的UNPAY("unpay",1)這些實例。實例的創建被簡化了,只需要調用構造函數,不需要用new關鍵字。

  其實,按照我的理解,上述的枚舉類可以用以下的類來代替。

  

package com.xdx.learn;

public class OrderMulti {
    private String key;
    private int value;
    private OrderMulti(String key,int value){
        this.key=key;
        this.value=value;
    }
    
    public String getKey() {
        return key;
    }
    public void setKey(String key) {
        this.key = key;
    }
    public int getValue() {
        return value;
    }
    public void setValue(int value) {
        this.value = value;
    }

    public static final OrderMulti UNPAY=new OrderMulti("unpay", 1);
    public static final OrderMulti UNDELIVER=new OrderMulti("undeliver", 2);
    public static final OrderMulti UNRECEIVE=new OrderMulti("unreceive", 3);
    public static final OrderMulti UNCOMMENT=new OrderMulti("uncomment", 4);
    public static void main(String args[]){
        System.out.println(OrderMulti.UNPAY.getKey());
        System.out.println(OrderMulti.UNPAY.getValue());
    }

}

  沒錯,枚舉類就相當於一個帶有多例(多例模式)的java類。只不過java的語法幫我們做了這些顯式實例化的操作,並且以一種比較簡單的語法來表示。就變成了enum了。

  3.再深入一點,其實枚舉類都是Enum類的子類,去查jdk源碼,發現Enum是一個抽象的泛型類,其定義為public abstract class Enum<E extends Enum<E>>
implements Comparable<E>, Serializable。事實上,上述的OrderEnum類,可以理解成這樣的一個類。

  public class OrderEnum extends Enum<OrderEnum>,沒錯,泛型的類型實參就是這個枚舉類本身。

  不過當你真的在eclipse裏面敲入上面的一個類,會發現報錯,因為Enum這個類是不可繼承的,提示的錯誤是The type OrderEnum may not subclass Enum<A> explicitly。不能顯式的繼承Enum。jdk在編譯階段就拒絕了一個類去繼承Enum,具體什麽原因,怎麽實現,我也不知道。我們只需要知道enum修飾的類,它的父類是Enum就行了。

  既然如此,enum修飾的類也就不可以在繼承其他的類了,因為java是單繼承的。當然可以通過實現接口的方式去對enum類進行擴展。

  由於枚舉類繼承自Enum,那麽Enum裏面的一些方法他也可以用。看如下代碼,使用了幾個比較常用的方法。

  

    public static void main(String args[]){
        System.out.println(OrderEnum.UNPAY.getKey());
        System.out.println(OrderEnum.UNPAY.getValue());
        //name()方法獲取該枚舉類實例的名稱
        System.out.println(OrderEnum.UNPAY.name());
        //ordinal()方法獲取該枚舉類實例在所有實例中的排序,從0開始。
        System.out.println(OrderEnum.UNPAY.ordinal());
        //compareTo()方法比較兩個枚舉實例的排序,可認為是前者的ordinal-後者的ordinal的值。
        System.out.println(OrderEnum.UNPAY.compareTo(OrderEnum.UNDELIVER));
        System.out.println(OrderEnum.UNRECEIVE.compareTo(OrderEnum.UNDELIVER));
        System.out.println(OrderEnum.UNCOMMENT.compareTo(OrderEnum.UNDELIVER));
        //獲取該枚舉對象的類
        System.out.println(OrderEnum.UNPAY.getDeclaringClass());
        //驗證枚舉類的父類確實是Enum
        System.out.println(OrderEnum.UNPAY.getDeclaringClass().getSuperclass());
        System.out.println(OrderEnum.UNPAY.equals(OrderEnum.UNCOMMENT));
        //遍歷枚舉類中實例
        for(OrderEnum orderenum:OrderEnum.values()){
            System.out.println(orderenum.getKey());
        }
    }

  上述代碼的運行結果為:

  unpay
  1
  UNPAY
  0
  -1
  1
  2
  class com.xdx.learn.OrderEnum
  class java.lang.Enum
  false
  unpay
  undeliver

  unreceive
  uncomment

  4.只要將枚舉理解成一個實現了多例模式的類,運用起來就不會有什麽困難。但是也有人會問,我用第一種方式,即直接使用一個public static final int UNPAY=1。這樣的常量。不是也可以實現枚舉需要的功能嗎?為何還大費周章去定義一個枚舉類呢?我覺得是基於如下幾方面考慮的。

  (1)首先枚舉類的類名可以有一定的指示作用,比如我們給一個枚舉類命名為week,我們可以知道它應該就是代表星期,而在枚舉之前,我們使用常量的容器類,往往只定義一個類,命名為類似於Constant這樣的類,要去裏面找尋其中的常量值是比較費勁的。

  (2)當用枚舉作為函數的形參的時候,能起到限定的作用。比如我有一個函數 ,我可以定義為void func(int x),接受一些常量值。我也可以定義成void func(OrderEnum orderEnum)這樣的形式。後者比前者的優點在於它限制了傳入的參數只能是該枚舉類的實例,而前者則可以傳入任意整型。

  

java枚舉細節