當需要一組固定常量的時候,應該使用enum代替int常量,除了對于手機登資源有限的設備應該酌情考慮enum的性能弱勢之外。
枚舉的ordinal()方法會返回枚舉常量在類型中的數字位置, 但是盡量不要使用它,因為當重新排序后,會對客戶端造成破壞。 正確的做法是,將他保存在一個實例域中。
應該給enum添加int域,而不是使用ordinal方法來導出與枚舉關聯的序數值。(幾乎不應使用ordinal方法,除非在編寫像EnumMap這樣的基于枚舉的通用數據結構)
//WRONGpublic enum Fruit{ APPLE, PEAR, ORANGE; public int numberOfFruit(){ return ordinal() + 1; }}//RIGHTpublic enum Fruit{ APPLE(1), PEAR(2), ORANGE(3); PRivate final int number; Fruit(int num) {number = num;} public int numberOfFruit(){ return number; }}每個EnumSet的內容都表示為位矢量。如若底層的枚舉類型個數小于64個,則整個EnumSet就用單個long來表示,因此性能上比的上位域。
//WRONGpublic 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) {...}}//usetext.applyStyles(STYLE_BOLD | STYLE_ITALIC);//RIGHTpublic class Text{ public enum Style{STYLE_BOLD, STYLE_ITALIC, STYLE_UNDERLINE} public void applyStyles(Set<Style> styles) {...} //這里不使用EnumSet<Style>參數是因為考慮到某些客戶端可能會傳遞一些其他的Set實現}//usetext.applyStyles(EnumSet.of(STYLE_BOLD, STYLE_ITALIC));EnumSet 實現了 Set 接口,提供了豐富的功能,類型安全.可以從其他任何Set中得到互換性.整個 EnumSet 就是用 單個 long 來表示的,性能上比得上 位運算的性能.總而言之因為枚舉類型要用在集合(Set)中,所以沒有理由用位域來表示.序數索引是指依賴于枚舉成員在枚舉中的序數來進行數組索引,如:
//定義了植物類,其中植物又分為水果,蔬菜,樹木三種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<…>>
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
優先使用注解來表面針對某些程序元素的特定信息。 注解的優勢:
@Retention : 限定保留時期@Target: 限定其應用的程序元素還有很多注解,如 @IntDef,@ViewDebug…注解接收的參數如果是數組,為其賦值一個單獨的元素也是合法的在想要覆蓋的方法上使用Override注解,編譯器就可以幫助發現一些錯誤。可以不寫Override的特例:在具體類中不必標注你確信覆蓋了抽象方法聲明的方法(雖然這么做也沒有什么壞處)。
標記分為標記接口和標記注解。
標記接口:沒有包含方法聲明的接口,只是指明某個類實現了具有某種屬性的接口。比如Serializable接口,通過實現這個接口,類表明它的實例可以被寫到ObjectOutputStream。。
標記接口與標記注解的最終要的區別在于: 標記接口可以在編譯時就檢查到相應的類型問題,而標記注解則要到運行時。
標記接口優勢:
標記接口定義的類型是由 被標記的類的實例 實現的,標記注解 則沒有定義這樣的類型他們可以被更加精確的進行鎖定,比如 如果注解類型利用 @Target(ElementType.TYPE) 標記,則它可以被應用到任何類或者接口上標記注解優勢:
它可以 通過默認的方式 添加 一個或者多個注解類型元素,給 已被使用的注解類型添加更多的信息.隨著時間的推移,簡單的標記注解類型可以演變成更加豐富的注解類型.他們是更大的注解機制的一部分.使用:
如果標記是應用到任何程序元素而不是類或者接口,就必須使用注解. 因為只有 類和接口可以用來實現或者擴展接口如果標記只應用給類和接口,就應該 優先使用標記接口而非注解《Effective Java中文版 第2版》PDF版下載: http://download.csdn.net/detail/xunzaosiyecao/9745699
作者:jiankunking 出處:http://blog.csdn.net/jiankunking
新聞熱點
疑難解答