Enum?(feat.定数)


ていすう


Enumを理解する前に,定数について簡単に論じた.
定数は不変の値です.
int x = 1; //좌항 변수, 우항 상수
1 = 2; // 1은 2가 될 수 없다. 

議長なら...?🎃


定数のこのような特性を利用して、以下の論理を書くことができます.
 
public class ConstantDemo {
    public static void main(String[] args) {
        /*
         * 1. 사과
         * 2. 복숭아
         * 3. 바나나
         */
        int type = 1;
        switch(type){
            case 1:
                System.out.println(57);
                break;
            case 2:
                System.out.println(34);
                break;
            case 3:
                System.out.println(93);
                break;
        }
    }
 
}
上記の論理では、数字1に対応する果物はいつでも謝罪しなければならない.
注釈が失われたり,注釈とコードとの距離が遠くなったりする場合,コードを理解することは困難である.
コメントより良いコードは「コメントがなくても」理解できるコード!

Namespaceラーメン…?🎃


上に名前があればいいのに.変数は定数であってもよい.変数を指定し、最終的に処理すればよい.また、値が変わらない場合は、インスタンス変数ではなくクラス変数(static)として指定することが望ましい.
 
public class ConstantDemo {
    private final static int APPLE = 1;
    private final static int PEACH = 2;
    private final static int BANANA = 3;
    public static void main(String[] args) {
        int type = APPLE;
        switch(type){
            case APPLE:
                System.out.println(57+" kcal");
                break;
            case PEACH:
                System.out.println(34+" kcal");
                break;
            case BANANA:
                System.out.println(93+" kcal");
                break;
        }
    }
}
しかし番組の拡大に伴い、企業に対する定数が増加した.
public class ConstantDemo {
    // fruit
    private final static int APPLE = 1;
    private final static int PEACH = 2;
    private final static int BANANA = 3;
     
    // company
    private final static int GOOGLE = 1;
    //private final static int APPLE = 2;
    private final static int ORACLE = 3;
     
    public static void main(String[] args) {
        int type = APPLE;
        switch(type){
            case APPLE:
                System.out.println(57+" kcal");
                break;
            case PEACH:
                System.out.println(34+" kcal");
                break;
            case BANANA:
                System.out.println(93+" kcal");
                break;
        }
    }
}
この場合、果物APPLEと企業APPLEは同じ名称を有する.
APPLEの値が2から1になると定数の概念に反するためエラーが発生します.
(error : Duplicate field ConstantDemo.APPLE)
これらの問題を解決するために、接頭辞を付けましょう.
public class ConstantDemo {
    // fruit
    private final static int FRUIT_APPLE = 1;
    private final static int FRUIT_PEACH = 2;
    private final static int FRUIT_BANANA = 3;
     
    // company
    private final static int COMPANY_GOOGLE = 1;
    private final static int COMPANY_APPLE = 2;
    private final static int COMPANY_ORACLE = 3;
     
    public static void main(String[] args) {
        int type = FRUIT_APPLE;
        switch(type){
            case FRUIT_APPLE:
                System.out.println(57+" kcal");
                break;
            case FRUIT_PEACH:
                System.out.println(34+" kcal");
                break;
            case FRUIT_BANANA:
                System.out.println(93+" kcal");
                break;
        }
    }
}

インターフェイスなら…?🎃


このように変更すると、重複する名前の確率が低下します.この手法をネーミングスペースと呼ぶ.
しかし、水が散らかっています.きれいに交換するために、インタフェースを使ってみましょう.
interface FRUIT{
    int APPLE=1, PEACH=2, BANANA=3;
}
interface COMPANY{
    int GOOGLE=1, APPLE=2, ORACLE=3;
}
 
public class ConstantDemo {
     
    public static void main(String[] args) {
        int type = FRUIT.APPLE;
        switch(type){
            case FRUIT.APPLE:
                System.out.println(57+" kcal");
                break;
            case FRUIT.PEACH:
                System.out.println(34+" kcal");
                break;
            case FRUIT.BANANA:
                System.out.println(93+" kcal");
                break;
        }
    }
}
インタフェースがこのように使用できるのは、インタフェースで宣言された変数が無条件に共通の静的fianl属性を持つためです.

あの…。もういいです。🎃


しかし、タイプとしてCOMPANY GOGLEを使う人がいたらどうなるのでしょうか.下図のように変更します.
int type = COMPANY.GOOGLE;
結果は57 Kcal!グーグルは57 Kcalです.
私たちのコードには2つの常配列があります.果物と企業です.
異なるカテゴリの値間では比較できませんが、2つの定数グループのデータ型は同じなので比較できます.コンパイラにこれらのエラーを事前に見つけてもらいたいです.
(異なるデータ型を設定できる場合?)
 
class Fruit{
    public static final Fruit APPLE  = new Fruit();
    public static final Fruit PEACH  = new Fruit();
    public static final Fruit BANANA = new Fruit();
}
class Company{
    public static final Company GOOGLE = new Company();
    public static final Company APPLE = new Company();
    public static final Company ORACLE = new Company();
}
 
public class ConstantDemo {
     
    public static void main(String[] args) {
        if(Fruit.APPLE == Company.APPLE){
            System.out.println("과일 애플과 회사 애플이 같다.");
        }
    }
}
FruitクラスとCompanyクラスを作成し、クラス変数をそのクラスのインスタンスとして使用しています.各変数はfinalなので、staticなのでインスタンスを作成する必要はありません.コンパイルエラーが発生します.これが私たちが望んでいることです.異なるカテゴリの定数に対しては比較さえ禁止されている.エラーはコンパイル時に発生するはずです.実行中に発生したエラーは検出しにくい.
しかし、上記のコードには2つの問題があります.1つはswitch文が使用できないこと、2つは宣言が複雑すぎることです.
だから…!!!

Enum👍


Enumを列挙型(列挙タイプ)と呼ぶ.列挙型は相互に関連する定数の集合といえる.上記の例では、FruitとCompanyがリストされています.このモードはjava 1.5から文法的にサポートされ、列挙型である.以前のコードをenumに変えましょう.
enum Fruit{
    APPLE, PEACH, BANANA;
}
enum Company{
    GOOGLE, APPLE, ORACLE;
}
 
public class ConstantDemo {
     
    public static void main(String[] args) {
        /*
        if(Fruit.APPLE == Company.APPLE){
            System.out.println("과일 애플과 회사 애플이 같다.");
        }
        */
        Fruit type = Fruit.APPLE;
        switch(type){
            case APPLE:
                System.out.println(57+" kcal");
                break;
            case PEACH:
                System.out.println(34+" kcal");
                break;
            case BANANA:
                System.out.println(93+" kcal");
                break;
        }
    }
}
上のコードでは
enum Fruit{
    APPLE, PEACH, BANANA;
}
Enumはclass,interfaceと同等のフォーマットを持つ単位である.しかしenumは実際にはclassです.便宜上、enumのみに使用される構文フォーマットを有するため、区別するためにenumというキーワードが使用される.上のコードは実際には下のコードと同じです.
class Fruit{
    public static final Fruit APPLE  = new Fruit();
    public static final Fruit PEACH  = new Fruit();
    public static final Fruit BANANA = new Fruit();
    private Fruit(){}
}
作成者のアクセス制御者はprivateです.これはクラスFruitがインスタンスとして使用できないことを意味します.他の用途に使用することは禁止されています.これについては、後で説明します.Enumは言語が多くの場所で使用されている設計モデルを採用し、文法要素に簡略化していると言える.
次のコードでコンパイルエラーが発生します.
/*
if(Fruit.APPLE == Company.APPLE){
    System.out.println("과일 애플과 회사 애플이 같다.");
}
*/
これはenumがコンパイル時に異なる定数グループの比較を遮断できることを意味する.enumも定数グループでクラスを作成する効果があることがわかります.

enumを使うメリット

  • コードは簡単になります.
  • インスタンスの生成と継承を防止します.
  • キーワードenumを用いたので,実現の意図を明確に示すことができる.
  • Enumは実はクラスです.したがって、ジェネレータを持つことができます.次のようにコードを変更します.
    enum Fruit{
        APPLE, PEACH, BANANA;
        Fruit(){
            System.out.println("Call Constructor "+this);
        }
    }
     
    enum Company{
        GOOGLE, APPLE, ORACLE;
    }
     
    public class ConstantDemo {
         
        public static void main(String[] args) {
         
            /*
            if(Fruit.APPLE == Company.APPLE){
                System.out.println("과일 애플과 회사 애플이 같다.");
            }
            */
            Fruit type = Fruit.APPLE;
            switch(type){
                case APPLE:
                    System.out.println(57+" kcal");
                    break;
                case PEACH:
                    System.out.println(34+" kcal");
                    break;
                case BANANA:
                    System.out.println(93+" kcal");
                    break;
            }
        }
    }
    結果は以下の通りです.
    Call Constructor APPLE
    Call Constructor PEACH
    Call Constructor BANANA
    57 kcal
    Call Constructor出力は、ジェネレータFruitが呼び出されたことを意味します.これは3回呼び出され、フィールドの数と同じ数で呼び出されることを意味します.すなわち、enumはジェネレータを有することができる.
    ただし、コードを次のように変更すると、コンパイルエラーが発生します.
    enum Fruit{
        APPLE, PEACH, BANANA;
        public Fruit(){
            System.out.println("Call Constructor "+this);
        }
    }
    これはenumの作成者が制御者privateにのみアクセスできるためです.したがって、直接Fruitを生成することはできません.もしそうであれば、このジェネレータのパラメータ設定フィールド(APPLE...)インスタンス変数の値を指定できますか?あります.しかし、やり方は少し疎い.
    enum Fruit{
        APPLE("red"), PEACH("pink"), BANANA("yellow");
        public String color;
        Fruit(String color){
            System.out.println("Call Constructor "+this);
            this.color = color;
        }
    }
     
    enum Company{
        GOOGLE, APPLE, ORACLE;
    }
     
    public class ConstantDemo {
         
        public static void main(String[] args) {
            /*
            if(Fruit.APPLE == Company.APPLE){
                System.out.println("과일 애플과 회사 애플이 같다.");
            }
            */
            Fruit type = Fruit.APPLE;
            switch(type){
                case APPLE:
                    System.out.println(57+" kcal, "+Fruit.APPLE.color);
                    break;
                case PEACH:
                    System.out.println(34+" kcal"+Fruit.PEACH.color);
                    break;
                case BANANA:
                    System.out.println(93+" kcal"+Fruit.BANANA.color);
                    break;
            }
        }
    }
    実行結果は次のとおりです.
    Call Constructor APPLE
    Call Constructor PEACH
    Call Constructor BANANA
    57 kcal, red
    次のコードはFruitの定数を宣言し、ジェネレータを呼び出します.
    APPLE("red"), PEACH("pink"), BANANA("yellow");
    次のコードはジェネレータです.コンストラクション関数のパラメータとして渡される値はthisです.colorにより、5行のインスタンス変数の値に割り当てられます.
    Fruit(String color){
        System.out.println("Call Constructor "+this);
        this.color = color;
    }
    下図に示すように、呼び出しは、APPLEに割り当てられたFruitインスタンスのcolorフィールドを返します.
    System.out.println(57+" kcal, "+Fruit.APPLE.color);
    列挙型には方法がある可能性があります.次のコードは、前の例と同じ結果を出力します.
    enum Fruit{
        APPLE("red"), PEACH("pink"), BANANA("yellow");
        private String color;
        Fruit(String color){
            System.out.println("Call Constructor "+this);
            this.color = color;
        }
        String getColor(){
            return this.color;
        }
    }
     
    enum Company{
        GOOGLE, APPLE, ORACLE;
    }
     
    public class ConstantDemo {
         
        public static void main(String[] args) {
            Fruit type = Fruit.APPLE;
            switch(type){
                case APPLE:
                    System.out.println(57+" kcal, "+Fruit.APPLE.getColor());
                    break;
                case PEACH:
                    System.out.println(34+" kcal"+Fruit.PEACH.getColor());
                    break;
                case BANANA:
                    System.out.println(93+" kcal"+Fruit.BANANA.getColor());
                    break;
            }
        }
    }
    Enumは、すべてのメンバーをリストする機能も提供します.
    enum Fruit{
        APPLE("red"), PEACH("pink"), BANANA("yellow");
        private String color;
        Fruit(String color){
            System.out.println("Call Constructor "+this);
            this.color = color;
        }
        String getColor(){
            return this.color;
        }
    }
     
    enum Company{
        GOOGLE, APPLE, ORACLE;
    }
     
    public class ConstantDemo {
         
        public static void main(String[] args) {
            for(Fruit f : Fruit.values()){
                System.out.println(f+", "+f.getColor());
            }
        }
    }

    リファレンス


    https://opentutorials.org/course/1223/6091