JAvaにおける列挙タイプEnumの使い方

11877 ワード

以前はEnumについて漠然とした概念しかなかったが、最近はプロジェクトで使われるようになったので、専門的に研究してみた.
JAvaのEnum列挙タイプがついにj 2 se 1.5に登場した.前は鶏の肋骨にすぎないと思っていたが、あってもなくてもいい.結局ここ数年来、それがなければ、みんなよく暮らしているのではないでしょうか.今日『Thinking in Java』4 th editionを見てみると、「時にはそれだからこそ、あなたは「優雅で清潔」に問題を解決することができます.優雅さと明確さが重要で、正式には成功した解決策と失敗した解決策を区別しています.失敗した解決策は他の人が相手にできないからです.「Enum列挙タイプを使うと、以前は不器用だったコードを優雅に簡単にすることができますか?しかし、私は同時に別の問題を考えています.新しい技術を使うと、技術者にもっと負担をかけるのではないでしょうか.
「新しい言語を学ぶ危険の一つは、新しい文法構造を狂わせることだ」
 
        EnumはSunが新しく導入したキーワードとして、特殊なclassのように見えます.独自の変数もあり、独自の方法を定義することができ、1つ以上のインタフェースを実現することができます.enumタイプを宣言するとき、enumタイプには次のような特徴があることに注意してください.
1.publicのコンストラクション関数を持つことはできません.これにより、顧客コードがenumのインスタンスを新規作成できないことを保証できます.
2.すべての列挙値はpublic、static、finalです.この点に注意するのは列挙値だけです.通常のクラスで変数を定義するのと同じように、他の任意のタイプの非列挙変数を定義することができます.これらの変数は、使用したい修飾子を使用することができます.
3.Enumデフォルトではjava.lang.Comparableインタフェースが実装されています. 
4.EnumはtoStringメソッドを上書きするので、Color.Blue.toString()のデフォルトの戻り文字列"Blue"を呼び出す.
5.Enumは、toString法に対応するvalueOf法を提供する.valueOf(「Blue」)を呼び出すとColor.Blue.が返されるので、toStringメソッドを自分で書き換えるときは、valueOfメソッドを対応するように書き換える必要があることに注意してください.
6.Enumはvaluesメソッドも提供しており、このメソッドはすべての列挙値を簡単に巡回することができます.
7.Enumには、列挙値が列挙クラスにある順序を返すoridinalメソッドもあります.この順序は、列挙値が宣言された順序によって決まり、ここでColor.Red.ordinal()は0を返します.
これらの基本的な特性を理解して、それらをどのように使用するかを見てみましょう.
1.すべての列挙値を遍歴します.valuesの方法があることを知って、私たちは軽くForEachサイクルで列挙値を遍歴することができます.
for(Color    c:    Color.values())     
  System.out.println(“find    value:”    +    c);     

2.enumでメソッドと変数を定義します.たとえば、Colorにメソッドを追加してランダムに色を返すことができます. 
public    enum    Color    {     
     Red,     
     Green,     
     Blue;     
    
     /*     
     *              。     
     *(        sun   enum      size  ).     
     */     
     private    static    int    number    =    Color.values().length    ;     
    
     /**     
     *                  
     @return    a    random    enum    value.     
     */     
     public    static    Color    getRandomColor(){     
     long    random    =    System.currentTimeMillis()    %    number;     
     switch    ((int)    random){     
      case    0:     
       return    Color.Red;     
      case    1:     
       return    Color.Green;     
      case    2:     
       return    Color.Blue;     
      default    :    return    Color.Red;     
     }     
     }     
     }     

これは列挙タイプで変数とメソッドを定義するのと、一般クラスでメソッドと変数を定義するのとに何の違いもないことがわかります.唯一注意しなければならないのは、変数とメソッド定義がすべての列挙値定義の後ろに置かなければならないことです.そうしないと、コンパイラはエラーを与えます.3.オーバーライド(Override)toString、valueOfメソッドの前にenumがtoString、valueOfなどのメソッドを提供していることを知っていますが、デフォルトのtoStringメソッドをオーバーロードする必要がある場合が多いので、enumについてはどうすればいいのでしょうか.実はこれは普通のclassを覆うtoStringの方法と何の違いもありません.
 public    String    toString(){     
     switch    (this){     
     case    Red:     
      return    "Color.Red";     
     case    Green:     
      return    "Color.Green";     
     case    Blue:     
      return    "Color.Blue";     
     default:     
      return    "Unknow    Color";     
     }     
     }     

このとき、前のループコードで印刷されたのは
Color.Red
Color.Green
Color.Blue
ではなく
Red
Green
Blue.
TOStringは確かに被覆されていることがわかります.一般に,toStringを上書きする際にvalueOf法を同時に上書きし,それらの相互整合性を維持しなければならない.
4.コンストラクション関数を使用enumはpublicのコンストラクション関数を持つことはできませんが、privateのコンストラクション関数を定義してenum内部で使用することができます.やはりColorという例を使います.
 public    enum    Color    {     
     Red("This    is    Red"),     
     Green("This    is    Green"),     
     Blue("This    is    Blue");     
    
     private    String    desc;     
    
     Color(String    desc){     
     this.desc    =    desc;     
     }     
    
     public    String    getDesc(){     
     return    this.desc;     
     }     
    
     }     

ここでは、各色に説明情報を提供し、この説明情報を受け入れる構造関数を定義します.ここで、コンストラクション関数はpublicまたはprotectedではなく、コンストラクション関数が内部でのみ使用されることを保証し、顧客コードが値を列挙するインスタンスをnewできないことに注意してください.列挙値がpublic static finalの定数であることを知っているからだ.
5.特定のインタフェースを実装enumは変数と方法を定義できることを知っています.これは、1つのインタフェースを実装しても通常のclassと同じように、ここでは例を挙げません.
6.列挙値の独自のメソッドを定義します.前にenumのためにいくつかの方法を定義することができますが、実際には列挙値ごとに方法を定義することもできます.これにより,我々の前にtoStringを上書きした例をこのように書き換えることができる.
public    enum    Color    {     
     Red    {     
     public    String    toString(){     
      return    "Color.Red";     
     }     
     },     
     Green    {     
     public    String    toString(){     
      return    "Color.Green";     
     }     
     },     
     Blue{     
     public    String    toString(){     
      return    "Color.Blue";     
     }     
     };     
     }     

論理的に言えば、これは「グローバル」なtoString方法よりも明確である.総じて言えば、enumは新しい定義のタイプとして、プログラマーが書くコードをより簡単に分かりやすくしたいと思っているが、個人的にはenumを使う高級な特性をあまり必要としないと思っている.そうしないと、分かりやすい初志に反する.
 
まずenumの簡単な応用を学び、以下の簡潔なコードにはenumが提供するほとんどの機能が含まれています.
1.定義、遍歴、switch、enumset、enummapなどを含むenumの応用
package com.autonavi.test;

import java.util.EnumMap;

import java.util.EnumSet;

/**
 * Java    enum    
 * MyEnum          
 *                 ,    、     
 * public enum State{ON,OFF }         java  
 * @author heqingfei
 */

public class MyEnum {
	//     enum    ,    ON,OFF
	public enum State {
		ON, OFF
	}

	public enum country {
		China, Japan
	}

	//     
	public static void main(String[] args) {
		//     enum
		for (State s : State.values()) {
			System.out.println(s.name());
		}
		
		//     enum
		for (country c : country.values()) {
			System.out.println(c.name());
		}

		// switch enum     
		State switchState = State.OFF;
		switch (switchState) {
		case OFF:
			System.out.println("OFF");
			break;
		case ON:
			System.out.println("ON");
			break;
		}
		
		System.out.println("******EnumSet   ********");
		// EnumSet   
		EnumSet stateSet = EnumSet.allOf(State.class);
		for (State s : stateSet) {
			System.out.println(s);
		}
		
		System.out.println("******EnumMap   ********");
		//EnumMap   
		EnumMap stateMap = new EnumMap(State.class);
		stateMap.put(State.ON, "is On");
		stateMap.put(State.OFF, "is off");
		for (State s : State.values()) {
			System.out.println(s.name() + ":" + stateMap.get(s));
		}

		System.out.println("===================");
		//          
		State state1 = MyEnum.State.OFF;
		System.out.println(state1.name());
		System.out.println("===================");
		State[] state2 = MyEnum.State.values();
		for (State state : state2) {
			System.out.println(state.name());
		}
	}

}

 
以下の内容はつまらないかもしれませんが、絶対に見る価値があります.1.public class State{public static final int ON=1;public static final Int OFF=0;}
何か悪いことがあったら、みんなこのように長い時間を使っていますから、大丈夫ですよ.まず、タイプが安全ではありません.intであることを確認しなければなりません.次に、その範囲が0と1であることを確認しなければなりません.最後に、印刷されたとき、1と0しか見えません.
しかし、コードを見ていない人はあなたの企みを知らないso、あなたの古いpublic static final定数を捨てましょう.
2.enumクラスを作成し、通常のクラスと見なすことができます.他のクラスを継承することはできません.(javaは単一の継承であり、Enumを継承しています)他のメソッドを追加して、それ自体を上書きする方法があります.
3.switch()パラメータはenumを使用できます
4.values()メソッドは、コンパイラがenum定義に挿入するstaticメソッドであるため、enumインスタンスを親Enumにアップコンバートすると、values()にアクセスできなくなります.解決策:ClassにgetEnumConstants()メソッドがあるため、Enumインタフェースにvalues()メソッドがなくても、Classオブジェクトからすべてのenumインスタンスを取得できます.
5.enumからサブクラスを継承できません.enumの要素を拡張する必要がある場合は、1つのインタフェースの内部にインタフェースを実装する列挙を作成し、要素をグループ化します.列挙要素をグループ化します.
6.フラグの代わりにEnumSetを使用します.enumはメンバーが一意であることを要求しますが、enumでは追加要素を削除できません.
7.EnumMapのkeyはenumであり、valueは他のObjectオブジェクトである.
8.enumでは、プログラマがeunmインスタンスのメソッドを記述できるようにします.したがって、enumインスタンスごとに異なる動作を付与できます.
9.enumの職責チェーン(Chain of Responsibility)を使用します.これは設計モードの職責チェーンモードに関係します.様々な方法で1つの問題を解決します.その後、それらをリンクします.1つの要求が来たとき、チェーン内のソリューションが要求を処理できるまでチェーンを巡ります.
10.enumを使用したステータスマシン
11.enumを使用した多重配布
 
 
用法一:定数
JDK 1.5以前に定数を定義したのは、public static fianl.....です.ここで、列挙があり、関連する定数を1つの列挙タイプにグループ化することができ、列挙は定数よりも多くの方法を提供しています.
public enum Color {
  RED, GREEN, BLANK, YELLOW
}

 
用法二:switch
JDK 1.6以前のswitch文はint,char,enumタイプのみをサポートしており,列挙を用いることで,コードの可読性を向上させることができる.
enum Signal {
	GREEN, YELLOW, RED
}
public class TrafficLight {
	Signal color = Signal.RED;
	public void change() {
		switch (color) {
		case RED:
			color = Signal.GREEN;
			break;
		case YELLOW:
			color = Signal.RED;
			break;
		case GREEN:
			color = Signal.YELLOW;
			break;
		}
	}
}

 
使用法3:列挙に新しいメソッドを追加する
独自のメソッドをカスタマイズする場合は、enumインスタンスシーケンスの最後にセミコロンを追加する必要があります.Javaでは、enumインスタンスを定義する必要があります.
public enum Color {
	RED("  ", 1), GREEN("  ", 2), BLANK("  ", 3), YELLO("  ", 4);
	//     
	private String name;
	private int index;
	//     
	private Color(String name, int index) {
		this.name = name;
		this.index = index;
	}
	//     
	public static String getName(int index) {
		for (Color c : Color.values()) {
			if (c.getIndex() == index) {
				return c.name;
			}
		}
		return null;
	}
	// get set   
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getIndex() {
		return index;
	}
	public void setIndex(int index) {
		this.index = index;
	}
}

 
使用法四:列挙を上書きする方法
以下にtoString()メソッドオーバーライドの例を示す.
public enum Color {
	RED("  ", 1), GREEN("  ", 2), BLANK("  ", 3), YELLO("  ", 4);
	//     
	private String name;
	private int index;
	//     
	private Color(String name, int index) {
		this.name = name;
		this.index = index;
	}
	//    
	@Override
	public String toString() {
		return this.index+"_"+this.name;
	}
}

 
使用法五:インタフェースの実装
すべての列挙はjava.lang.Enumクラスから継承されます.Javaではマルチ継承はサポートされていないため、列挙オブジェクトは他のクラスを継承できません.
public interface Behaviour {
	void print();
	String getInfo();
}
public enum Color implements Behaviour{
	RED("  ", 1), GREEN("  ", 2), BLANK("  ", 3), YELLO("  ", 4);
	//     
	private String name;
	private int index;
	//     
	private Color(String name, int index) {
		this.name = name;
		this.index = index;
	}
//    
	@Override
	public String getInfo() {
		return this.name;
	}
	//    
	@Override
	public void print() {
		System.out.println(this.index+":"+this.name);
	}
}

使用法6:インタフェースを使用して列挙を整理する
public interface Food {
	enum Coffee implements Food{
		BLACK_COFFEE,DECAF_COFFEE,LATTE,CAPPUCCINO
	}
	enum Dessert implements Food{
		FRUIT, CAKE, GELATO
	}
}

 
使用法7:列挙集合の使用について
JAva.util.EnumSetとjava.util.EnumMapは2つの列挙集合です.EnumSetは集合の要素が重複しないことを保証します.EnumMapのkeyはenumタイプで、valueは任意のタイプであることができます.この2つの集合の使用についてはここでは説明しませんが、JDKドキュメントを参照してください.
 
 
次に、列挙タイプを符号化および復号するためのツールクラスを作成します.
private static String[] showCollectType = {"    ", "    "};

 
/**
	 *        
	 * @param collectType
	 * @return
	 */
	public static CollectType encodeCollectType(String collectType) {
		CollectType collType = CollectType.COLLSERVICE;
		if(collectType.equals("    ")) {
			collType = CollectType.COLLSERVICE;
		} else if(collectType.equals("    ")) {
			collType = CollectType.COLLPERFORM;
		}
		return collType;
	}

 
/**
	 *        
	 * @param collType
	 * @return
	 */
	public static String decodeCollectType(CollectType collType) {
		String collectType = "    ";
		if(collType.equals(CollectType.COLLSERVICE)) {
			collectType = "    ";
		} else if(collType.equals(CollectType.COLLPERFORM)) {
			collectType = "    ";
		}
		return collectType;
	}

 
/**
  *       
  */
 public static String[] getShowCollectType() {
  return showCollectType;
 }