java枚舉細節
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 staticfinal 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; privateOrderEnum(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(intvalue) { 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枚舉細節