聲明:原創作品,轉載時請注明文章來自SAP師太技術博客( 博/客/園www.cnblogs.com):m.survivalescaperooms.com/jiangzhengjun,并以超鏈接形式標明文章原始出處,否則將追究法律責任!原文鏈接:http://m.survivalescaperooms.com/jiangzhengjun/p/4255663.html 第六章 枚舉和注解30、 用enum代替int常量枚舉類型是指由一組固定的常量組成合法值的類型,例如一年中的季節或一副牌中的花色。在沒引入枚舉時,一般是聲明一組int常量,每個類型成員一個常量:
publicstaticfinalintAPPLE_FUJI= 0;
publicstaticfinalintAPPLE_PipPIN= 1;
publicstaticfinalintAPPLE_GRANNY_SMITH= 2;
publicstaticfinalintORANGE_NAVEL= 0;
publicstaticfinalintORANGE_TEMPLE= 1;
publicstaticfinalintORANGE_BLOOD= 2;
這種方法稱作int枚舉模式,存在很多不足,不具有類型安全與使用方便性。如果你將apple傳到一個想要接收orange的方法中,編譯器也不會出現警告,而且還可以使用==來比較apple與orange。
注意每個apple常量都以APPLE_作為前綴,每個orange常量都以ORANGE_作為前綴,這是因為可以防止名稱沖突。
采用int枚舉模式的程序是十分脆弱,因為int枚舉是編譯時常量,被編譯到使用它們的客戶端中。如果與枚舉常量關聯的int發生了變化,客戶端就必須重新編譯,如果不重新編譯,程序還是可以運行,但不是最新的值了。
另外從使用方便性來看,沒有便利的toString方法,打印出來的為數字,沒有多大的用處。要遍歷一組中所有的int枚舉常量,也沒有可靠的方法。
既然int枚舉常量有這么多的缺點,那使用String枚舉常如何?同樣也不是我們期望的。雖然在可以打印字符串,但它會導致性能問題,因為它依賴于字符串的比較操作。另外與int枚舉常量一樣會編譯到客戶端代碼中,編譯時難以發現,但會在運行時出錯。
幸運的是1.5版本開始,枚舉可以避免int和String枚舉模式的缺點,并提供許多額外的好處。下面是最簡單的形式:
publicenumApple{FUJI,PIPPIN,GRANNY_SMITH}
publicenumOrange{NAVEL,TEMPLE,BLOOD}
Java枚舉類型背后的基本想法很簡單:本質上是int值,它們是通過公有的靜態final域為每個枚舉常量導出實例的類。因為沒有可以訪問的構造器,枚舉類型是真正的final。因為客戶端即不能創建枚舉類型的實例,也不能對它進行擴展,因此對它進行實例化,而只有聲明過的枚舉常量。換句話說,枚舉類型是實例受控的。它們是單例的泛型化,本質上是單元素的枚舉。
枚舉提供了編譯時類型安全。如果聲明一個參數的類型為Apple,就可以保證,被傳到該參數上的任何非null的對象引用一定屬于三個有效的Apple值之一。試圖傳遞類型錯誤的值時,會導致編譯時錯誤,就像試圖將某種枚舉類型的表達式賦值給另一種枚舉類型的變量,或者試圖利用==操作符比較不同枚舉類型的值一樣,都會出錯。
枚舉提供了單獨的命名空間,同一系統中可以有多個同名的枚舉類型變量。你可以增加或者重新排序枚舉類型常量,而無需重新編譯它的客戶端代碼,因為導出常量的域在枚舉類型和它的客戶端之間提供了一個隔離層:常量值并沒有被編譯到客戶端代碼中,而是在int枚舉模式之中。最終,可以通過調用toString方法,將枚舉轉換成可打印的字符串。
除了完善了int枚舉模式不足外,枚舉還允許添加任意的方法和域,并實例任意接口,它們提供了所有Object(見第3章)的高級實現,實現了Comparable和Serializable接口,并針對枚舉型的可任意改變性設計了序列化方式。
如果一個枚舉具有普遍適用性,它就應該成為一個頂層類,如果它只是被用在一個特定的頂層類中,它就應該成為該頂層類的一個成員類。
可以為枚舉類型添加數據域與方法,下面是一個算術運行的枚舉類:
publicenumOperation {
PLUS("+") {
doubleapply(doublex,doubley) {
returnx + y;
}
},
MINUS("-") {
doubleapply(doublex,doubley) {
returnx - y;
}
},
TIMES("*") {
doubleapply(doublex,doubley) {
returnx * y;
}
},
DIVIDE("/") {
doubleapply(doublex,doubley) {
returnx / y;
}
};
PRivatefinalString symbol;//操作符:+ - * /
Operation(String symbol) {//構造函數,存儲操作符供toString打印使用
this.symbol = symbol;
}
@Override
//重寫Enum中的打印name的性為
publicString toString() {
returnsymbol;
}
//抽像方法,不同的常量具有不同的功能,需在每個常量類的主體里重寫它
abstractdoubleapply(doublex,doubley);
/*
* 初始化時,存儲操作符與枚舉常量的對應關系,用來實現fromString方法
* 這樣我們就可以通過操作符來獲取到對應的枚舉常量,有點像valueOf方法,
* 只不過它是通過枚舉常量的名字name來獲取常量的。這種通用的方法還可以
* 應用到其他枚舉類中
*/
privatestaticfinalMap<String, Operation>stringToEnum=newHashMap<String, Operation>();
static{ //從name到枚舉常量轉換到從某個域到枚舉常量的轉換
for(Operation op :values())
stringToEnum.put(op.toString(), op);
}
//根據操作符來獲取對應的枚舉常量,如果沒有返回null,模擬valueOf方法
publicstaticOperation fromString(String symbol) {
returnstringToEnum.get(symbol);
}
publicstaticvoidmain(String[] args) {
doublex = Double.parseDouble(args[0]);
doubley = Double.parseDouble(args[1]);
for(Operation op : Operation.values())
System.out.printf("%f %s %f = %f%n", x, op, y, op.apply(x, y));
for(Operation op : Operation.values())
System.out.printf("%f %s %f = %f%n", x, op, y, Operation
.fromString(op.toString()).apply(x, y));
}
}
在opr包下會看見Operation.class、Operation$4.class、Operation$2.class、Operation$3.class、Operation$1.class這樣幾個類,Operation$X.class都是繼承自Operation類,而Operation又繼承自Enum類,下面是反編譯這些類的代碼:
public abstract class opr.Operation extends java.lang.Enum{
Word-spacing: 0px; text-transform: none; word-break: normal; margin: 0cm 0cm 0pt; letter-spacing: normal; line-height: normal; text-indent: 0px; -webkit-text-size
新聞熱點
疑難解答