javaに深く入り込んで列挙種類のEnumソースコードを読みます(転載)
9251 ワード
この文章はエニュメレート・エンムのソースヘルプ文書です。もっと多くのソースコードは私のgithubを訪問してください。https://github.com/yangsheng20080808/deepIntoJava
転載元:http://www.hollischuang.com/archives/92
文章は4つの部分に分かれています。定義 メンバー変数 構築関数 他の方法 エンム
Enum類はjava.langカバンの中の一つです。彼はJava言語の中の全てのエニュメレート・タイプの公共基本類です。
定義
まず、抽象類は実用化できないので、javaプログラムではnewキーワードを使ってEnumを宣言することはできません。もし定義するなら、このような文法が使えます。
なぜ一つの抽象類は継承されないのですか?エンム定義の列挙はどうやって来ましたか?Enumへの継承ではないですか?これらの疑問を持って、次のコードを逆コンパイルします。
2.
EnumはSerializableインターフェースを実現しました。EnumはComprableインターフェースを実現し、比較ができます。デフォルトでは同じタイプのenumだけが比較を行います。異なるタイプのenumの間の比較を実現するには、compreToの方法を複写するしかありません。
3.泛型:
まず、このように書くのはJavaのAPIをより弾力的にするためだけで、彼は主に形態パラメータの実用化の対象を限定しているので、Enumだけが必要です。このようにしてこそ、compreToなどの方法で入ってきたパラメータを形態検査することができます。だから、彼がなぜこのように設計されたのかについて、私達は全く関心を持たなくてもいいです。
ここでは、一般的なextensの使い方に注目しても良いし、
はい、私達はこれに戻りました。本当に理解できない
まず私達はまず「翻訳」に来ました。この
なぜJavaはこのようにEnumを定義しますか?
まず、私達は科学普及に来ました。
この問題を理解するには、まずEnumクラスの方法を見ます。(他のメンバー変数と方法をしばらく無視します。)
でもJavaはEumを使います。
Javaは形態パラメータの実用化の対象を限定するために、Enumだけが必要であり、compreToなどの方法で入ってきたパラメータを形態検査することができます。「赤」は「緑」と比べてこそ意味があるので、「赤」と「春」のほうが無意味です。だから、Javaはこのような方法でcompreToのように正常に使うことができます。
Enumには2つのメンバー変数があります。一つは名前で、一つは番号です。シーケンス番号は、列挙の定数であり、列挙の位置を表し、0から順に増加します。
前に述べましたが、Enumは抽象的な類で、実用化されません。しかし、彼も構造関数を持っています。前から私達が逆コンパイルしたコードの中から、Enumの構造関数を見つけました。Eumの中には保護タイプの構造関数しかありません。
その他の方法
Enumには以下のようないくつかの一般的な方法があります。
参考資料:
java.lang.Enum
Java Generaics FAQs
転載元: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