Effective Java讀書筆記二:列舉和註解(30-37)
第30條:用enum代替int常量
當需要一組固定常量的時候,應該使用enum代替int常量,除了對於手機登資源有限的裝置應該酌情考慮enum的效能弱勢之外。
第31條:用例項域代替序數
列舉的ordinal()方法會返回列舉常量在型別中的數字位置, 但是儘量不要使用它,因為當重新排序後,會對客戶端造成破壞。 正確的做法是,將他儲存在一個例項域中。
應該給enum新增int域,而不是使用ordinal方法來匯出與列舉關聯的序數值。(幾乎不應使用ordinal方法,除非在編寫像EnumMap這樣的基於列舉的通用資料結構)
//WRONG
public enum Fruit{
APPLE, PEAR, ORANGE;
public int numberOfFruit(){
return ordinal() + 1;
}
}
//RIGHT
public enum Fruit{
APPLE(1), PEAR(2), ORANGE(3);
private final int number;
Fruit(int num) {number = num;}
public int numberOfFruit(){
return number;
}
}
第32條:用EnumSet代替位域
每個EnumSet的內容都表示為位向量。如若底層的列舉型別個數小於64個,則整個EnumSet就用單個long來表示,因此效能上比的上位域。
//WRONG
public class Text{
private static final int STYLE_BOLD = 1 << 0;
private static final int STYLE_ITALIC = 1 << 1;
private static final int STYLE_UNDERLINE = 1 << 2;
public void applyStyles(int styles) {...}
}
//use
text.applyStyles(STYLE_BOLD | STYLE_ITALIC);
//RIGHT
public class Text{
public enum Style{STYLE_BOLD, STYLE_ITALIC, STYLE_UNDERLINE}
public void applyStyles(Set<Style> styles) {...} //這裡不使用EnumSet<Style>引數是因為考慮到某些客戶端可能會傳遞一些其他的Set實現
}
//use
text.applyStyles(EnumSet.of(STYLE_BOLD, STYLE_ITALIC));
- EnumSet 實現了 Set 介面,提供了豐富的功能,型別安全.可以從其他任何Set中得到互換性.
- 整個 EnumSet 就是用 單個 long 來表示的,效能上比得上 位運算的效能.
- 總而言之因為列舉型別要用在集合(Set)中,所以沒有理由用位域來表示.
第33條:用EnumMap代替序數索引
序數索引是指依賴於列舉成員在列舉中的序數來進行陣列索引,如:
//定義了植物類,其中植物又分為水果,蔬菜,樹木三種
public class Plant{
public enum Type { Fruit, Vegetables, Tree}
private final String name;
private final Type type;
Plant(String name, Type type){
this.name = name;
this.type = type;
}
}
Set<Plant>[] plants = (Set<Plant>[]) new Set[Plant.Type.valuse().lenght];
//根據植物的型別,分別把所有的植物放入三個set中
for(int i = 0; i < plant.lenght; i++){
plant[i] = new HashSet<Plant>();
}
for(Plant p : garden){ //garden裡放了所有的植物
plant[p.type.ordinal()].add(p) //反面教材:利用了列舉的序數來得到想要的陣列索引,使用者在其他地方可以不使用ordinal函式,而直接使用int值來訪問,就可能出錯
}
應該使用EnumMap來實現,EnumMap內部是採用陣列實現的,具有Map的豐富功能和型別安全以及陣列 的效率:
Map<Plant.Type, Set<Plant>> plants = new EnumMap<Plant.Type, Set<Plant>>(Plant.Type.class); //建構函式需要 鍵 型別的Class物件
//根據植物的型別,分別把所有的植物放入三個set中
for(Plant.Type type : Plant.Type.valuse()){
plant.put(type, new HashSet<Plant>);
}
for(Plant p : garden){ //garden裡放了所有的植物
plant.get(p.type).add(p) //使用者必須使用正確的鍵值來訪問,即Type型別
}
當需要多維關係時,可以使用EnumMap<…, EnumMap<…>>
第34條:用介面模擬可以伸縮的列舉
1、如果讓一個 列舉型別 去擴充套件另一個 列舉型別,利用語言的特性,幾乎是不可能的
2、列舉的可擴充套件性,到最後都證明不是一個好點子.
由於在java中enum不是可擴充套件的,在某些情況下,可能需要對列舉進行擴充套件,比如操作型別(+-*/等),就可以考慮:
1.定義一個介面,比如public interface Operation{…};
2.使列舉繼承介面:比如public enum BasicOperation implements Operation{…}
3.使用時的API寫成介面(比如,T extends Enum & Operation),而不是實現(比如BasicOperation )
private static <T extends Enum<T> & Operation> void function(T t,..); //表示T即表示列舉又是Operation的子型別
4.當需要擴充套件BasicOperation列舉時,就可以另寫一個列舉,且implements介面Operation
第35條:註解優先於命名模式
優先使用註解來表面針對某些程式元素的特定資訊。
註解的優勢:
- @Retention : 限定保留時期
- @Target: 限定其應用的程式元素
- 還有很多註解,如 @IntDef,@ViewDebug…
- 註解接收的引數如果是陣列,為其賦值一個單獨的元素也是合法的
第36條:堅持使用Override註解
在想要覆蓋的方法上使用Override註解,編譯器就可以幫助發現一些錯誤。可以不寫Override的特例:在具體類中不必標註你確信覆蓋了抽象方法宣告的方法(雖然這麼做也沒有什麼壞處)。
第37條:用標記介面實現型別
標記分為標記介面和標記註解。
標記介面:沒有包含方法宣告的介面,只是指明某個類實現了具有某種屬性的介面。比如Serializable介面,通過實現這個介面,類表明它的例項可以被寫到ObjectOutputStream。。
標記介面與標記註解的最終要的區別在於:
標記介面可以在編譯時就檢查到相應的型別問題,而標記註解則要到執行時。
標記介面優勢:
- 標記介面定義的型別是由 被標記的類的例項 實現的,標記註解 則沒有定義這樣的型別
- 他們可以被更加精確的進行鎖定,比如
如果註解型別利用 @Target(ElementType.TYPE) 標記,則它可以被應用到任何類或者介面上
標記註解優勢:
- 它可以 通過預設的方式 新增 一個或者多個註解型別元素,給 已被使用的註解型別新增更多的資訊.隨著時間的推移,簡單的標記註解型別可以演變成更加豐富的註解型別.
- 他們是更大的註解機制的一部分.
使用:
- 如果標記是應用到任何程式元素而不是類或者介面,就必須使用註解. 因為只有 類和介面可以用來實現或者擴充套件介面
- 如果標記只應用給類和介面,就應該 優先使用標記介面而非註解
《Effective Java中文版 第2版》PDF版下載:
http://download.csdn.net/detail/xunzaosiyecao/9745699
作者:jiankunking 出處:http://blog.csdn.net/jiankunking
相關文章
- Effective Java 讀書筆記Java筆記
- 《Effective Java 第二版》讀書筆記Java筆記
- Effective Java 讀書筆記(2)Java筆記
- Effective Java讀書筆記(目錄)Java筆記
- 《effective java》讀書筆記1(建立和銷燬物件)Java筆記物件
- 《Effective-Ruby》讀書筆記筆記
- 《Effective C#》讀書筆記C#筆記
- 《Effective C++》讀書筆記C++筆記
- Java列舉類、註解和反射Java反射
- 【Java基礎】列舉和註解Java
- Effective Java讀書筆記六:方法(38-44)Java筆記
- Effective Java讀書筆記八:巢狀類(22)Java筆記巢狀
- 《More Effective C#》讀書筆記C#筆記
- Effective Java讀書筆記三:建立和銷燬物件(1-7)Java筆記物件
- Effective Java讀書筆記一:併發(66-73)Java筆記
- Effective Java讀書筆記五:異常(57-65)Java筆記
- Java列舉解讀Java
- Java列舉類與註解詳解——一篇文章讀懂列舉類與註解詳Java
- Effective Java讀書筆記八:序列化(74-78)Java筆記
- Day69.註解&列舉類的複習 -Java註解&列舉類Java
- Effective Java讀書筆記四:通用程式設計(45-56)Java筆記程式設計
- Effective Java - 構造器私有、列舉和單例Java單例
- 《effective java》讀書筆記2(對於所有物件都通用的方法)Java筆記物件
- Effective Java讀書筆記七:泛型(23-29 部分章節需要重讀)Java筆記泛型
- Java基礎(十)——列舉與註解Java
- 《Effective Objective-C 2.0》讀書/實戰筆記 一Object筆記
- 《Effective C++》第5章 實現-讀書筆記C++筆記
- 《Effective C++》第8章 定製new和delete-讀書筆記C++delete筆記
- The Great Gatsby讀書筆記(二)筆記
- TIJ讀書筆記(二) (轉)筆記
- [心得] Effective Java心得筆記Java筆記
- java讀書筆記---垃圾回收Java筆記
- Java 列舉、JPA 和 PostgreSQL 列舉JavaSQL
- 《Effective C++》第3章 資源管理(2)-讀書筆記C++筆記
- 《Effective C++》第3章 資源管理(1)-讀書筆記C++筆記
- Spring Boot Transactional註解原始碼閱讀筆記(二)Spring Boot原始碼筆記
- 《Java8實戰》-讀書筆記第二章Java筆記
- Java 學習筆記 二維陣列和物件陣列Java筆記陣列物件