javaに深く入り込んで列挙種類のEnumソースコードを読みます(転載)


この文章はエニュメレート・エンムのソースヘルプ文書です。もっと多くのソースコードは私のgithubを訪問してください。https://github.com/yangsheng20080808/deepIntoJava
転載元:http://www.hollischuang.com/archives/92
文章は4つの部分に分かれています。
  • 定義
  • メンバー変数
  • 構築関数
  • 他の方法
  • エンム
    Enum類はjava.langカバンの中の一つです。彼はJava言語の中の全てのエニュメレート・タイプの公共基本類です。
    定義
    public abstract class Enum> implements Comparable, Serializable
    
    1.抽象類
    まず、抽象類は実用化できないので、javaプログラムではnewキーワードを使ってEnumを宣言することはできません。もし定義するなら、このような文法が使えます。
    enum enumName{
        value1,value2
        method1(){}
        method2(){}
    }
    
    次に、抽象類を見ると、第一印象は必ず類が彼を継承している。少なくとも私達は彼を受け継ぐことができるはずです。だから:
    /**
     * @author hollis
     */
    public class testEnum extends Enum{
    }
    public class testEnum extends Enum>{
    }
    public class testEnum extends Enum>{
    }
    
    以上の3つの方法を試した結果、Enum類は引き継げないという結論が出ました。
    なぜ一つの抽象類は継承されないのですか?エンム定義の列挙はどうやって来ましたか?Enumへの継承ではないですか?これらの疑問を持って、次のコードを逆コンパイルします。
      enum Color {RED, BLUE, GREEN}
    
    コンパイラは彼を以下のように変更します。
    /**
     * @author hollis
     */
    public final class Color extends Enum {
      public static final Color[] values() { return (Color[])$VALUES.clone(); }
      public static Color valueOf(String name) { ... }
    
      private Color(String s, int i) { super(s, i); }
    
      public static final Color RED;
      public static final Color BLUE;
      public static final Color GREEN;
    
      private static final Color $VALUES[];
    
      static {
        RED = new Color("RED", 0);
        BLUE = new Color("BLUE", 1);
        GREEN = new Color("GREEN", 2);
        $VALUES = (new Color[] { RED, BLUE, GREEN });
      }
    } 
    
    短い一行のコードですが、コンパイラで処理されてからこんなに多くなりました。どうやら、enmuのキーワードはjavaが提供してくれた文法飴ですね。逆コンパイルのコードから、コンパイラは私たちにEnumを引き継がせないことを発見しました。しかし、エンムキーを使って列挙を定義すると、彼はコンパイル後にjava.lang.Enum類をデフォルトで継承してくれます。他のクラスのようにObject類を黙認して継承します。また、enum声明を採用すると、クラスはコンパイラにfinal声明を加えられますので、クラスは継承できません。PS:JVMクラス初期化はスレッドの安全性のため、エニュメレーションクラスを採用してスレッドの安全を実現する単一の例モードです。
    2.Comparable及びSerializableインターフェースを実現する。
    EnumはSerializableインターフェースを実現しました。EnumはComprableインターフェースを実現し、比較ができます。デフォルトでは同じタイプのenumだけが比較を行います。異なるタイプのenumの間の比較を実現するには、compreToの方法を複写するしかありません。
    3.泛型:**>**どうやって理解しますか?
    まず、このように書くのはJavaのAPIをより弾力的にするためだけで、彼は主に形態パラメータの実用化の対象を限定しているので、Enumだけが必要です。このようにしてこそ、compreToなどの方法で入ってきたパラメータを形態検査することができます。だから、彼がなぜこのように設計されたのかについて、私達は全く関心を持たなくてもいいです。
    ここでは、一般的なextensの使い方に注目しても良いし、> K V O T E 142 object 142 142 142 142 142 142のこれらのシンボルの違いに注目しても良い。
    はい、私達はこれに戻りました。本当に理解できない>です。
    まず私達はまず「翻訳」に来ました。このEnum>はどういう意味ですか?そして、なぜJavaがこのように使うのかを説明します。まず一般的な汎型を見ます。Listです。この汎型は、Listに存在するのはStringタイプで、コンパイラがStringタイプを受け入れるようにと言っています。そしてListから内容を取り出す時も自動的にStringタイプに変えてくれるという意味です。したがって、Enum>は、Enumの内容は全部E extends Enumタイプであると一時的に理解することができる。ここのEはエニュメレーションとして理解し、extensは上界を表し、例えばList extends Object>、Listの内容はObjectまたはObjectから拡張されたクラスであってもよい。これがextensの意味です。したがって、E extends Enumは、Enumのタイプを引き継ぐエニュメレート・タイプであると表している。では、Enum>は、一つのEnumが一つのEnumまたは彼のサブクラスだけをパラメータとして受け入れるということが分かります。一つのサブクラスや自分をパラメータとして、自分自身に伝えて、特別な文法効果を引き起こします。
    なぜJavaはこのようにEnumを定義しますか?
    まず、私達は科学普及に来ました。
    /**
     * @author hollis
     */
    enum Color{
        RED,GREEN,YELLOW
    }
    enum Season{
        SPRING,SUMMER,WINTER
    }
    public class EnumTest{
        public static void main(String[] args) {
            System.out.println(Color.RED.ordinal());
            System.out.println(Season.SPRING.ordinal());
        }
    }
    
    コードの中で2つの出力内容は全部0です。エニュメレート・タイプのデフォルトの番号は全部ゼロから始まります。
    この問題を理解するには、まずEnumクラスの方法を見ます。(他のメンバー変数と方法をしばらく無視します。)
    /**
     * @author hollis
     */
    public abstract class Enum<E extends Enum<E>> implements Comparable<E>, Serializable {
            private final int ordinal;
    
            public final int compareTo(E o) {
            Enum other = (Enum)o;
            Enum self = this;
            if (self.getClass() != other.getClass() && // optimization
                self.getDeclaringClass() != other.getDeclaringClass())
                throw new ClassCastException();
            return self.ordinal - other.ordinal;
        }
    }
    まず、Enumの定義にはEnumは使われていないと思います。
    public final int compareTo(Object o) 
    compreToメソッドを呼び出した時、依然として二つのエニュメレート・タイプが入ってきました。compreTo方法の実現において、二つのエニュメレーションを比較する過程はまずパラメータをEnumタイプに変換してから、彼らの番号が等しいかどうかを比較します。じゃ私達はこう比較します。
    Color.RED.compareTo(Color.RED);
    Color.RED.compareTo(Season.SPRING);
    compreToメソッドで何の処理もしないと、これらのコードの返却内容はtrueです。(Season.SPRINGの番号とColor.REDの番号は全部0ですから)。しかし、Color.REDとSeason.SPRINGは同じではないことは明らかです。
    でもJavaはEumを使います。
    The method compareTo(Color) in the type Enum<Color> is not applicable for the arguments (Season)
    彼は、compreTo方法はEnumタイプだけを受け入れると説明しました。
    Javaは形態パラメータの実用化の対象を限定するために、Enumだけが必要であり、compreToなどの方法で入ってきたパラメータを形態検査することができます。「赤」は「緑」と比べてこそ意味があるので、「赤」と「春」のほうが無意味です。だから、Javaはこのような方法でcompreToのように正常に使うことができます。
           PS: Java ,       “  ” “  ”  ,  Enum   Comparable  ,    compareTo        enum     。
    
    メンバー変数
    Enumには2つのメンバー変数があります。一つは名前で、一つは番号です。シーケンス番号は、列挙の定数であり、列挙の位置を表し、0から順に増加します。
    /**
     * @author hollis
     */
    private final String name;
    public final String name() {
        return name;
    }
    private final int ordinal;
    public final int ordinal() {
        return ordinal;
    }
    
    構造関数
    前に述べましたが、Enumは抽象的な類で、実用化されません。しかし、彼も構造関数を持っています。前から私達が逆コンパイルしたコードの中から、Enumの構造関数を見つけました。Eumの中には保護タイプの構造関数しかありません。
    protected Enum(String name, int ordinal) {
        this.name = name;
        this.ordinal = ordinal;
    }
    
    記事の先頭に逆コンパイルされたコードの中のprivate Color(String s, int i) { super(s, i); }は、Enumの中のこのタイプの保護構造関数を呼び出して、nameとordinalを初期化することである。
    その他の方法
    Enumには以下のようないくつかの一般的な方法があります。
    public String toString() {
        return name;
    }
    
    public final boolean equals(Object other) {
        return this==other;
    }
    
    public final int hashCode() {
        return super.hashCode();
    }
    
    public final int compareTo(E o) {
        Enum other = (Enum)o;
        Enum self = this;
        if (self.getClass() != other.getClass() && // optimization
            self.getDeclaringClass() != other.getDeclaringClass())
            throw new ClassCastException();
        return self.ordinal - other.ordinal;
    }
    
    public final Class getDeclaringClass() {
        Class clazz = getClass();
        Class zuper = clazz.getSuperclass();
        return (zuper == Enum.class) ? clazz : zuper;
    }
    
    public static > T valueOf(Class enumType,String name) {
        T result = enumType.enumConstantDirectory().get(name);
        if (result != null)
            return result;
        if (name == null)
            throw new NullPointerException("Name is null");
        throw new IllegalArgumentException(
            "No enum constant " + enumType.getCanonicalName() + "." + name);
    }
    
    方法は簡単です。普段使えるものも多くないので、ここでは詳しく紹介しません。
    参考資料:
    java.lang.Enum
    Java Generaics FAQs