<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    thinking

    one platform thousands thinking

    java enum 學(xué)習(xí)

    關(guān)鍵字: java enum 在像C這樣強(qiáng)調(diào)數(shù)據(jù)結(jié)構(gòu)的語言里,枚舉是必不可少的一種數(shù)據(jù)類型。然而在java的早期版本中,是沒有一種叫做enum的獨(dú)立數(shù)據(jù)結(jié)構(gòu)的。所以在以前的java版本中,我們經(jīng)常使用interface來simulate一個(gè)enum
    java 代碼
    1. public interface Color {   
    2.     static int RED  = 1;   
    3.     static int GREEN    = 2;   
    4.     static int BLUE = 3;   
    5. }  

    雖然這種simulation比較麻煩,但在以前也還應(yīng)付的過去。可是隨著java語言的發(fā)展,越來越多的呼聲要求把enum這種數(shù)據(jù)結(jié)構(gòu)獨(dú)立出來,加入到java中。所以從java 1.5以后,就有了enum,這也是這篇blog要學(xué)習(xí)的topic。

    學(xué)習(xí)的最好方式就是例子,先來一個(gè):

    java 代碼
    1. public class EnumDemo {   
    2.     private enum Color {red, blue, green}//there is not a ";"   
    3.        
    4.     public static void main(String[] args) {   
    5.         for(Color s : Color.values()) {   
    6.             //enum的values()返回一個(gè)數(shù)組,這里就是Seasons[]   
    7.             System.out.println(s);   
    8.         }   
    9.     }   
    10. }  
    console results
    1. red   
    2. blue   
    3. green  

    注意事項(xiàng)已經(jīng)在code中注釋出,還要說明一點(diǎn)的是,這個(gè)java文件編譯完成后不只有一個(gè)EnumDemo.class,還會(huì)有一個(gè)EnumDemo$Seasons.class,奇怪吧!

    Another e.g.

    java 代碼
    1. public class EnumDemo {   
    2.     private enum Color {red, blue, green}//there is not a ";"   
    3.        
    4.     public static void main(String[] args) {   
    5.         Color s = Color.blue;   
    6.            
    7.         switch (s) {   
    8.         case red://notice: Seasons.red will lead to compile error   
    9.             System.out.println("red case");   
    10.             break;   
    11.         case blue:   
    12.             System.out.println("blue case");   
    13.             break;   
    14.         case green:   
    15.             System.out.println("green case");   
    16.             break;   
    17.         default:   
    18.             break;   
    19.         }   
    20.     }   
    21. }  

    這個(gè)例子要說明的就是case的情況。

    就這么多嗎,當(dāng)然不是,我們的enum結(jié)構(gòu)還可以定義自己的方法和屬性。

    java 代碼
    1. public class EnumDemo {   
    2.     private enum Color {   
    3.         red, blue, green;//there is a ";"   
    4.            
    5.         //notic: enum's method should be "static"   
    6.         public static Color getColor(String s){   
    7.             if(s.equals("red flag")){   
    8.                 return red;   
    9.             } else if(s.equals("blue flag")){   
    10.                 return blue;   
    11.             } else {   
    12.                 return green;   
    13.             }   
    14.         }   
    15.     }//there is not ";"   
    16.        
    17.     public static void main(String[] args) {   
    18.         EnumDemo demo = new EnumDemo();   
    19.         System.out.println(demo.getFlagColor("red flag"));   
    20.     }   
    21.        
    22.     public Color getFlagColor(String string){   
    23.         return Color.getColor(string);   
    24.     }   
    25. }  
    Ok,so much for enum. Isn't it simple?.




    本文摘自IBM DW,如有轉(zhuǎn)載,請(qǐng)聲明!
    枚舉類型入門
    ----用 Java 5.0 以類型安全的方式表示常量
    Tiger 中的一個(gè)重要新特性是枚舉構(gòu)造,它是一種新的類型,允許用常量來表示特定的數(shù)據(jù)片斷,而且全部都以類型安全的形式來表示。Tiger 專家、developerWorks 的多產(chǎn)作者 Brett McLaughlin 將解釋枚舉的定義,介紹如何在應(yīng)用程序中運(yùn)用枚舉,以及它為什么能夠讓您拋棄所有舊的 public static final 代碼。
    您已經(jīng)知道,Java 代碼的兩個(gè)基本的構(gòu)造塊是 類和 接口。現(xiàn)在 Tiger 又引入了 枚舉,一般簡稱它為 enum。這個(gè)新類型允許您表示特定的數(shù)據(jù)點(diǎn),這些數(shù)據(jù)點(diǎn)只接受分配時(shí)預(yù)先定義的值集合。
    當(dāng)然,熟練的程序員可以用靜態(tài)常量實(shí)現(xiàn)這項(xiàng)功能,如清單 1 所示:
    清單 1. public static final 的常量
    public class OldGrade {
    public static final int A = 1;
    public static final int B = 2;
    public static final int C = 3;
    public static final int D = 4;
    public static final int F = 5;
    public static final int INCOMPLETE = 6;
    }

    摘者注:下面這段話說明了上述編程的弊端(除了這里所說的內(nèi)容外,摘者認(rèn)為如果OldGrade類中只有這些常量的話,應(yīng)該將其定義為接口,這樣可以防止錯(cuò)誤的實(shí)例化這個(gè)類)
    然后您就可以讓類接受像 OldGrade.B 這樣的常量,但是在這樣做的時(shí)候,請(qǐng)記住這類常量是 Java 中 int 類型的常量,這意味著該方法可以接受任何int類型的值,即使它和 OldGrade 中定義的所有級(jí)別都不對(duì)應(yīng)。因此,您需要檢測上界和下界,在出現(xiàn)無效值的時(shí)候,可能還要包含一個(gè) IllegalArgumentException 。而且,如果后來又添加另外一個(gè)級(jí)別(例如 OldGrade.WITHDREW_PASSING ),那么必須改變所有代碼中的上界,才能接受這個(gè)新值。
    換句話說,在使用這類帶有整型常量的類時(shí),該解決方案也許可行,但并不是非常有效。幸運(yùn)的是,枚舉提供了更好的方法。
    定義枚舉
    清單 2 使用了一個(gè)可以提供與清單 1 相似的功能的枚舉:
    清單 2. 簡單的枚舉類型
    package com.oreilly.tiger.ch03;
    public enum Grade {
    A, B, C, D, F, INCOMPLETE
    };
    在這里,我使用了新的關(guān)鍵字 enum ,為 enum 提供了一個(gè)名稱,并指定了允許的值。然后, Grade 就變成了一個(gè) 枚舉類型,您可以按清單 3 所示的方法使用它:
    清單 3. 使用枚舉類型
    package com.oreilly.tiger.ch03;
    public class Student {
    priv
    ate Grade grade;
    public void assignGrade(Grade grade) {
        this.grade = grade;
    }
    public Grade getGrade() {
        return grade;
    }
    public static void main(String[] args) {
    Student std = new Student();
                  std.assignGrade(Grade.A);
                  System.out.println(std.getGrade());
    }
    }
    用以前定義過的類型建立一個(gè)新的枚舉( grade )之后,您就可以像使用其他成員變量一樣使用它了。當(dāng)然,枚舉只能分配枚舉值中的一個(gè)(例如, A 、 C 或 INCOMPLETE )。而且,在 assignGrade() 中是沒有進(jìn)行錯(cuò)誤檢測的代碼,也沒有考慮邊界情況,請(qǐng)注意這是如何做到。
    (摘者注:摘者將上面的使用枚舉類型的類代碼進(jìn)行了修改,將一些設(shè)置學(xué)生姓名等內(nèi)容刪除,并將構(gòu)造函數(shù)也刪除,只留下對(duì)說明枚舉類型有作用的代碼,并添加 了main方法來進(jìn)行g(shù)rade的設(shè)置和獲取并打印,程序執(zhí)行結(jié)果為A,由于使用枚舉類型在方法assignGrade的參數(shù)中定義的是枚舉類型,而不是 java的int類型,所以傳遞的參數(shù)必須是枚舉類型參數(shù),而枚舉類型參數(shù)中定義的值都是合法的)。
    使用枚舉值
    迄今為止,您所看到的示例都相當(dāng)簡單,但是枚舉類型提供的東西遠(yuǎn)不止這些。您可以逐個(gè)遍歷枚舉值,也可以在 switch 語句中使用枚舉值,枚舉是非常有價(jià)值的。
    遍歷枚舉值
    下面我們用一個(gè)示例顯示如何遍歷枚舉類型的值。清單 4 所示的這項(xiàng)技術(shù),適用于調(diào)試、快速打印任務(wù)以及把枚舉加載到集合(我很快將談到)中的工具:
    清單 4. 遍歷枚舉值
    將上面的main方法修改為如下內(nèi)容:
    public static void main(String[] args) {
                                for (Grade g : Grade.values()) {
                                              System.out.println("Allowed value: '" + g + "'");
                                }
                  }
    運(yùn)行這段代碼,將得到清單 5 所示的輸出:
    清單 5. 迭代操作的輸出
    Allowed Value: 'A'
    Allowed Value: 'B'
    Allowed Value: 'C'
    Allowed Value: 'D'
    Allowed Value: 'F'
    Allowed Value: 'INCOMPLETE'
    這里有許多東西。首先,我使用了 Tiger 的新的 for/in 循環(huán)(也叫作 foreach 或 增強(qiáng)的 for )。另外,您可以看到 values() 方法返回了一個(gè)由獨(dú)立的 Grade 實(shí)例構(gòu)成的數(shù)組,每個(gè)數(shù)組都有一個(gè)枚舉類型的值。換句話說, values() 的返回值是 Grade[] 。
    在枚舉間切換
    能夠在枚舉的值之間移動(dòng)很好,但是更重要的是根據(jù)枚舉的值進(jìn)行決策。您當(dāng)然可以寫一堆 if (grade.equals(Grade.A)) 類型的語句,但那是在浪費(fèi)時(shí)間。Tiger 能夠很方便地把枚舉支持添加到過去的好東西 switch 語句上,所以它很容易使用,而且適合您已知的內(nèi)容。清單 6 向?qū)⒄故救绾谓鉀Q這個(gè)難題:
    清單 6. 在枚舉之間切換
    public static void main(String[] args) {
                                Student std = new Student();
                                std.assignGrade(Grade.INCOMPLETE);
                                switch (std.getGrade()) {
                                case A:
                                              System.out.println("excelled with a grade of A");
                                              break;
                                case B: // fall through to C
                                case C:
                                              System.out.println("passed with a grade of "
                                                                          + std.getGrade().toString());
                                              break;
                                case D: // fall through to F
                                case F:
                                              System.out.println("failed with a grade of "+ std.getGrade().toString());
                                              break;
                                case INCOMPLETE:
                                              System.out.println("did not complete the class.");
                                              break;
                                }
                  }
    在這里,枚舉值被傳遞到 switch 語句中(請(qǐng)記住, getGrade() 是作為 Grade 的實(shí)例返回的),而每個(gè) case 子句將處理一個(gè)特定的值。該值在提供時(shí)沒有枚舉前綴,這意味著不用將代碼寫成 case Grade.A ,只需將其寫成 case A 即可。如果您不這么做,編譯器不會(huì)接受有前綴的值。
    現(xiàn)在,您應(yīng)該已經(jīng)了解使用 switch 語句時(shí)的基本語法,但是還有一些事情您需要知道。
    在使用 switch 之前進(jìn)行計(jì)劃
    正如您所期待的,在使用枚舉和 switch 時(shí),您可以使用 default 語句。清單 7 顯示了這個(gè)用法:
    清單 7. 添加一個(gè) default 塊
    public static void main(String[] args) {
                   Student std = new Student();
                                std.assignGrade(Grade.INCOMPLETE);
                                switch (std.getGrade()) {
                                case A:
                                              System.out.println("excelled with a grade of A");
                                              break;
                                case B: // fall through to C
                                case C:
                                              System.out.println("passed with a grade of "+ std.getGrade().toString());
                                              break;
                                case D: // fall through to F
                                case F:
                                              System.out.println("failed with a grade of "
                                                                          + std.getGrade().toString());
                                              break;
                                case INCOMPLETE:
    System.out.println("did not complete the class.");
                                              break;
                                }
                 default:
               System.out.println("has a grade of "+std.getGrade().toString());
          break;
                  }

    研究以上代碼可以看出,任何沒有被 case 語句處理的枚舉值都會(huì)被 default 語句處理。這項(xiàng)技術(shù)您應(yīng)當(dāng)堅(jiān)持采用。原因是:假設(shè) Grade 枚舉被您的小組中其他程序員修改(而且他忘記告訴您這件事)成清單 8 所示的版本:
    清單 8. 給 Grade 枚舉添加一個(gè)值
    package com.oreilly.tiger.ch03;
    public enum Grade {
    A, B, C, D, F, INCOMPLETE
            ,
    WITHDREW_PASSING, WITHDREW_FAILING
    };
    現(xiàn)在,如果使用清單 6 的代碼所示的新版 Grade ,那么這兩個(gè)新值會(huì)被忽略。更糟的是,您甚至看不到錯(cuò)誤!在這種情況下,存在某種能夠通用的 default 語句是非常重要的。清單 7 無法很好地處理這些值,但是它會(huì)提示您還有其他值,您需要處理這些值。一旦完成處理,您就會(huì)有一個(gè)繼續(xù)運(yùn)行的應(yīng)用程序,而且它不會(huì)忽略這些值,甚至還會(huì)指 導(dǎo)您下一步的動(dòng)作。所以這是一個(gè)良好的編碼習(xí)慣。
    枚舉和集合
    您所熟悉的使用 public static final 方法進(jìn)行編碼的那些東西,可能已經(jīng)轉(zhuǎn)而采用枚舉的值作為映射的鍵。如果您不知道其中的含義,請(qǐng)參見清單 9,它是一個(gè)公共錯(cuò)誤信息的示例,在使用 Ant 的 build 文件時(shí),可能會(huì)彈出這樣的消息,如下所示:
    清單 9. Ant 狀態(tài)碼
    package com.oreilly.tiger.ch03;
    public enum AntStatus {
    INITIALIZING,
    COMPILING,
    COPYING,
    JARRING,
    ZIPPING,
    DONE,
    ERROR
    }為每個(gè)狀態(tài)碼分配一些人們能讀懂的錯(cuò)誤信息,從而允許人們在 Ant 提供某個(gè)代碼時(shí)查找合適的錯(cuò)誤信息,將這些信息顯示在控制臺(tái)上。這是映射(Map) 的一個(gè)絕好用例,在這里,每個(gè)映射(Map) 的鍵都是一個(gè)枚舉值,而每個(gè)值都是鍵的錯(cuò)誤信息。清單 10 演示了該映射的工作方式:
    清單 10. 枚舉的映射(Map)
    public void testEnumMap(PrintStream out) throws IOException {
    // Create a map with the key and a String message
    EnumMap<AntStatus, String> antMessages =
        new EnumMap<AntStatus, String>(AntStatus.class);
    // Initialize the map
    antMessages.put(AntStatus.INITIALIZING, "Initializing Ant...");
    antMessages.put(AntStatus.COMPILING,    "Compiling Java classes...");
    antMessages.put(AntStatus.COPYING,      "Copying files...");
    antMessages.put(AntStatus.JARRING,      "JARring up files...");
    antMessages.put(AntStatus.ZIPPING,      "ZIPping up files...");
    antMessages.put(AntStatus.DONE,         "Build complete.");
    antMessages.put(AntStatus.ERROR,        "Error occurred.");
    // Iterate and print messages
    for (AntStatus status : AntStatus.values() ) {
        out.println("For status " + status + ", message is: " +
                    antMessages.get(status));
    }
    }
    該代碼使用了泛型(generics)(請(qǐng)參閱 參考資料)和新的 EnumMap 構(gòu)造來建立新映射。而且,枚舉值是通過其 Class 對(duì)象提供的,同時(shí)提供的還有映射值的類型(在該例中,它只是一個(gè)簡單的字符串)。該方法的輸出如清單 11 所示:

    清單 11. 清單 10 的輸出
    For status INITIALIZING,message is: Initializing Ant...
    For status COMPILING, message is: Compiling Java classes...
    For status COPYING, message is: Copying files...
    For status JARRING, message is: JARring up files...
    For status ZIPPING, message is: ZIPping up files...
    For status DONE, message is: Build complete.
    For status ERROR, message is: Error occurred.
    更進(jìn)一步
    枚舉也可以與集合結(jié)合使用,而且非常像新的EnumMap構(gòu)造,Tiger 提供了一套新的EnumSet實(shí)現(xiàn),允許您使用位操作符。另外,可以為枚舉添加方法,用它們實(shí)現(xiàn)接口,定義叫作特定值的類的實(shí)體,在該實(shí)體中,特定的代碼 被附加到枚舉的具體值上。這些特性超出了本文的范圍,但是在其他地方,有詳細(xì)介紹它們的文檔(請(qǐng)參閱參考資料)。
    使用枚舉,但是不要濫用
    學(xué)習(xí)任何新版語言的一個(gè)危險(xiǎn)就是瘋狂使用新的語法結(jié)構(gòu)。如果這樣做,那么您的代碼就會(huì)突然之間有 80% 是泛型、標(biāo)注和枚舉。所以,應(yīng)當(dāng)只在適合使用枚舉的地方才使用它。那么,枚舉在什么地方適用呢?一條普遍規(guī)則是,任何使用常量的地方,例如目前用 switch代碼切換常量的地方。如果只有單獨(dú)一個(gè)值(例如,鞋的最大尺寸,或者籠子中能裝猴子的最大數(shù)目),則還是把這個(gè)任務(wù)留給常量吧。但是,如果定 義了一組值,而這些值中的任何一個(gè)都可以用于特定的數(shù)據(jù)類型,那么將枚舉用在這個(gè)地方最適合不過。
    摘者將Sun Java 5.0對(duì)于類型安全的Enum的說明拷貝放在下邊,以供參考:
    In prior releases, the standard way represent an enumerated type was the int Enum pattern: public static final int SEASON_WINTER = 0;
    public static final int SEASON_SPRING = 1;
    public static final int SEASON_SUMMER = 2;
    public static final int SEASON_FALL   = 3;
    This pattern has many problems, such as:

    Not typesafe - Since a season is just an int you can pass in any other int value where a season is required, or add two seasons together (which makes no sense).
    No namespace - You must prefix constants of an int enum with a string (in this case SEASON_) to avoid collisions with other int enum types.
    Brittleness - Because int enums are compile-time constants, they are compiled into clients that use them. If a new constant is added between two existing constants or the order is changed, clients must be recompiled. If they are not, they will still run, but their behavior will be undefined.
    Printed values are uninformative - Because they are just ints, if you print one out all you get is a number, which tells you nothing about what it represents, or even what type it is.

    It is possible to get around these problems by using the Typesafe Enum pattern (see Effective Java Item 21), but this pattern has its own problems: It is quite verbose, hence error prone, and its enum constants cannot be used in switch statements.
    In Tiger, the Java™ programming language gets linguistic support for enumerated types. In their simplest form, these enums look just like their C, C++, and C# counterparts:
    enum Season { WINTER, SPRING, SUMMER, FALL }
    But appearances can be deceiving. Java programming language enums are far more powerful than their counterparts in other languages, which are little more than glorified integers. The new enum declaration defines a full-fledged class (dubbed an enum type). In addition to solving all the problems mentioned above,

    it allows you to add arbitrary methods and fields to an enum type, to implement arbitrary interfaces, and more. Enum types provide high-quality implementations of all the Object methods. They are Comparable and Serializable, and the serial form is designed to withstand arbitrary changes in the enum type.
    Here is an example of a playing card class built atop a couple of simple enum types. The Card class is immutable, and only one instance of each Card is created, so it need not override equals or hashCode:
    import java.util.*;

    public class Card {
        public enum Rank { DEUCE, THREE, FOUR, FIVE, SIX,
            SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE }

        public enum Suit { CLUBS, DIAMONDS, HEARTS, SPADES }

        private final Rank rank;
        private final Suit suit;
        private Card(Rank rank, Suit suit) {
            this.rank = rank;
            this.suit = suit;
        }

        public Rank rank() { return rank; }
        public Suit suit() { return suit; }
        public String toString() { return rank + " of " + suit; }

        private static final List<Card> protoDeck = new ArrayList<Card>();

        // Initialize prototype deck
        static {
            for (Suit suit : Suit.values())
                for (Rank rank : Rank.values())
                    protoDeck.add(new Card(rank, suit));
        }

        public static ArrayList<Card> newDeck() {
            return new ArrayList<Card>(protoDeck); // Return copy of prototype deck
        }
    }
    The toString method for Card takes advantage of the toString methods for Rank and Suit. Note that the Card class is short (about 25 lines of code). If the typesafe enums (Rank and Suit) had been built by hand, each of them would have been significantly longer than the entire Card class.
    The (private) constructor of Card takes two parameters, a Rank and a Suit. If you accidentally invoke the constructor with the parameters reversed, the compiler will politely inform you of your error. Contrast this to the int enum pattern, in which the program would fail at run time.
    Note that each enum type has a static values method that returns an array containing all of the values of the enum type in the order they are declared. This method is commonly used in combination with the for-each loop to iterate over the values of an enumerated type.
    The following example is a simple program called Deal that exercises Card. It reads two numbers from the command line, representing the number of hands to deal and the number of cards per hand. Then it creates a new deck of cards, shuffles it, and deals and prints the requested hands.
    import java.util.*;

    public class Deal {
        public static void main(String args[]) {
            int numHands = Integer.parseInt(args[0]);
            int cardsPerHand = Integer.parseInt(args[1]);
            List<Card> deck = Card.newDeck();
            Collections.shuffle(deck);
            for (int i=0; i < numHands; i++)
                System.out.println(deal(deck, cardsPerHand));
        }

        public static ArrayList<Card> deal(List<Card> deck,

    int n) {
             int deckSize = deck.size();
             List<Card> handView = deck.subList(deckSize-n, deckSize);
             ArrayList<Card> hand = new ArrayList<Card>(handView);
             handView.clear();
             return hand;
         }
    }

    $ java Deal 4 5
    [FOUR of HEARTS, NINE of DIAMONDS, QUEEN of SPADES, ACE of SPADES, NINE of SPADES]
    [DEUCE of HEARTS, EIGHT of SPADES, JACK of DIAMONDS, TEN of CLUBS, SEVEN of SPADES]
    [FIVE of HEARTS, FOUR of DIAMONDS, SIX of DIAMONDS, NINE of CLUBS, JACK of CLUBS]
    [SEVEN of HEARTS, SIX of CLUBS, DEUCE of DIAMONDS, THREE of SPADES, EIGHT of CLUBS]
    Suppose you want to add data and behavior to an enum. For example consider the planets of the solar system. Each planet knows its mass and radius, and can calculate its surface gravity and the weight of an object on the planet. Here is how it looks:
    public enum Planet {
        MERCURY (3.303e+23, 2.4397e6),
        VENUS   (4.869e+24, 6.0518e6),
        EARTH   (5.976e+24, 6.37814e6),
        MARS    (6.421e+23, 3.3972e6),
        JUPITER (1.9e+27,   7.1492e7),
        SATURN (5.688e+26, 6.0268e7),
        URANUS (8.686e+25, 2.5559e7),
        NEPTUNE (1.024e+26, 2.4746e7),
        PLUTO   (1.27e+22, 1.137e6);

        private final double mass;   // in kilograms
        private final double radius; // in meters
        Planet(double mass, double radius) {
            this.mass = mass;
            this.radius = radius;
        }

    private double mass()   { return mass; }
        private double radius() { return radius; }

        // universal gravitational constant (m3 kg-1 s-2)
        public static final double G = 6.67300E-11;

        double surfaceGravity() {
            return G * mass / (radius * radius);
        }
        double surfaceWeight(double otherMass) {
            return otherMass * surfaceGravity();
        }
    }
    The enum type Planet contains a constructor, and each enum constant is declared with parameters to be passed to the constructor when it is created.
    Here is a sample program that takes your weight on earth (in any unit) and calculates and prints your weight on all of the planets (in the same unit):
        public static void main(String[] args) {
            double earthWeight = Double.parseDouble(args[0]);
            double mass = earthWeight/EARTH.surfaceGravity();
            for (Planet p : Planet.values())
               System.out.printf("Your weight on %s is %f%n",
                                 p, p.surfaceWeight(mass));
        }

    $ java Planet 175
    Your weight on MERCURY is 66.107583
    Your weight on VENUS is 158.374842
    Your weight on EARTH is 175.000000
    Your weight on MARS is 66.279007
    Your weight on JUPITER is 442.847567
    Your weight on SATURN is 186.552719
    Your weight on URANUS is 158.397260
    Your weight on NEPTUNE is 199.207413
    Your weight on PLUTO is 11.703031
    The idea of adding behavior to enum consta

    nts can be taken one step further. You can give each enum constant a different behavior for some method. One way to do this by switching on the enumeration constant. Here is an example with an enum whose constants represent the four basic arithmetic operations, and whose eval method performs the operation:
    public enum Operation {
        PLUS, MINUS, TIMES, DIVIDE;

        // Do arithmetic op represented by this constant
        double eval(double x, double y){
            switch(this) {
                case PLUS:   return x + y;
                case MINUS: return x - y;
                case TIMES: return x * y;
                case DIVIDE: return x / y;
            }
            throw new AssertionError("Unknown op: " + this);
        }
    }
    This works fine, but it will not compile without the throw statement, which is not terribly pretty. Worse, you must remember to add a new case to the switch statement each time you add a new constant to Operation. If you forget, the eval method with fail, executing the aforementioned throw statement
    There is another way give each enum constant a different behavior for some method that avoids these problems. You can declare the method abstract in the enum type and override it with a concrete method in each constant. Such methods are known as constant-specific methods. Here is the previous example redone using this technique:
    public enum Operation {
    PLUS   { double eval(double x, double y) { return x + y; } },
    MINUS { double eval(double x, double y) { return x - y; } },
    TIMES { double eval(double x, double y) { return x * y; } },
    DIVIDE { double eval(double x, double y) { return x / y; } }// Do arithmetic op represented by this constant
    abstract double eval(double x, double y);
    }
    Here is a sample program that exercises the Operation class. It takes two operands from the command line, iterates over all the operations, and for each operation, performs the operation and prints the resulting equation:
        public static void main(String args[]) {
            double x = Double.parseDouble(args[0]);
            double y = Double.parseDouble(args[1]);
            for (Operation op : Operation.values())
                System.out.printf("%f %s %f = %f%n", x, op, y, op.eval(x, y));
        }

    $ java Operation 4 2
    4.000000 PLUS 2.000000 = 6.000000
    4.000000 MINUS 2.000000 = 2.000000
    4.000000 TIMES 2.000000 = 8.000000
    4.000000 DIVIDE 2.000000 = 2.000000
    Constant-specific methods are reasonably sophisticated, and many programmers will never need to use them, but it is nice to know that they are there if you need them.
    Two classes have been added to java.util in support of enums: special-purpose Set and Map implementations called EnumSet and EnumMap. EnumSet is a high-performance Set implementation for enums. All of the members of an enum set must be of the same enum type. Internally, it is represented by a bit-vector, typically a single long. Enum sets support iteration over ranges of enum types. For example given the following enum declaration:
        enum Day { SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY }
    you can iterate over the weekdays. The EnumSet class provides a static factory that makes it easy:
        for (Day d : EnumSet.range(Day.MONDAY, Day.FRIDAY))
            System.out.println(d);
    Enum sets also provide a rich,typesafe replacement for traditional bit flags:
        EnumSet.of(Style.BOLD, Style.ITALIC)
    Similarly, EnumMap is a high-performance Map implementation for use with enum keys, internally implemented as an array. Enum maps combine the richness and safety of the Map interface with speed approaching that of an array. If you want to map an enum to a value, you should always use an EnumMap in preference to an array.
    The Card class, above, contains a static factory that returns a deck, but there is no way to get an individual card from its rank and suit. Merely exposing the constructor would destroy the singleton property (that only a single instance of each card is allowed to exist). Here is how to write a static factory that preserves the singleton property, using a nested EnumMap:
    private static Map<Suit, Map<Rank, Card>> table =
        new EnumMap<Suit, Map<Rank, Card>>(Suit.class);
    static {
        for (Suit suit : Suit.values()) {
            Map<Rank, Card> suitTable = new EnumMap<Rank, Card>(Rank.class);
            for (Rank rank : Rank.values())
                suitTable.put(rank, new Card(rank, suit));
            table.put(suit, suitTable);
        }
    }

    public static Card valueOf(Rank rank, Suit suit) {
        return table.get(suit).get(rank);
    }
    The EnumMap (table) maps each suit to an EnumMap that maps each rank to a card. The lookup performed by the valueOf method is internally implemented as two array accesses, but the code is much clearer and safer. In order to preserve the singleton property, it is imperative that the constructor invocation in the prototype deck initialization in Card be replaced by a call to the new static factory:
        // Initialize prototype deck
        static {


           for (Suit suit : Suit.values())
                for (Rank rank : Rank.values())
                    protoDeck.add(Card.valueOf(rank, suit));
        }
    It is also imperative that the initialization of table be placed above the initialization of protoDeck, as the latter depends on the former.
    So when should you use enums? Any time you need a fixed set of constants. That includes natural enumerated types (like the planets, days of the week, and suits in a card deck) as well as other sets where you know all possible values at compile time, such as choices on a menu, rounding modes, command line flags, and the like. It is not necessary that the set of constants in an enum type stay fixed for all time. The feature was specifically designed to allow for binary compatible evolution of enum types.

    如果本文對(duì)您有幫助并且要鼓勵(lì)我的話,請(qǐng)掃描如下二維碼支持本人的勞動(dòng)成果,多謝了!


    posted on 2009-12-21 16:41 lau 閱讀(10148) 評(píng)論(0)  編輯  收藏 所屬分類: J2SE

    主站蜘蛛池模板: 国产免费一区二区三区免费视频| 4480yy私人影院亚洲| 亚洲第一区精品日韩在线播放| 成年人免费观看视频网站| 成年女人毛片免费播放视频m | 亚洲国产av一区二区三区丶| 亚洲人成亚洲精品| 久久久久亚洲AV无码网站| 亚洲精品国产专区91在线| 亚洲精品综合久久中文字幕| 亚洲宅男天堂a在线| 亚洲 日韩 色 图网站| 亚洲精品自偷自拍无码| 激情小说亚洲图片| 丝袜足液精子免费视频| 国内精品免费视频精选在线观看 | 一级午夜a毛片免费视频| 一级看片免费视频囗交| 中文在线日本免费永久18近| 在线观看特色大片免费网站| 午夜免费福利视频| 日本在线高清免费爱做网站| 成人性生交视频免费观看| 成年女人永久免费观看片| 亚洲精品黄色视频在线观看免费资源| 久久久久亚洲AV成人网人人网站 | 亚洲av女电影网| 亚洲欧洲精品在线| 亚洲精品无播放器在线播放| 四虎国产精品成人免费久久| 日韩免费高清播放器| 皇色在线视频免费网站| 国产乱子伦精品免费女| 亚洲AV无码久久精品成人| 亚洲剧场午夜在线观看| 国产精品亚洲一区二区三区| a毛片视频免费观看影院| 亚洲免费福利在线视频| 亚洲成a人片在线观看久| 亚洲成a人片77777老司机| 亚洲精品天堂在线观看|