Java列挙メソッド-反対方向の列挙を返す


113

反対方向を返すメソッドを持つ列挙型Directionを宣言したいと思います(以下は構文的に正しくありません。つまり、列挙型はインスタンス化できませんが、私のポイントを示しています)。これはJavaで可能ですか?

これがコードです:

public enum Direction {

     NORTH(1),
     SOUTH(-1),
     EAST(-2),
     WEST(2);

     Direction(int code){
          this.code=code;
     }
     protected int code;
     public int getCode() {
           return this.code;
     }
     static Direction getOppositeDirection(Direction d){
           return new Direction(d.getCode() * -1);
     }
}

スイッチを使用するだけです。あなたは4ケースしかない。
Sotirios Delimanolis 2013

12
ちなみに、d.getCode() * -1==-d.getCode()
tckmn 2013

Blochの効果的なJavaの第6章(少なくとも2Eでは)は興味深いものであり、強くお勧めします。
jedwards 2013

ntu.edu.sg/home/ehchua/programming/java/javaenum.html、セクション2.1は、コンセプトをきちんと説明しています
vikramvi

回答:


205

タイトルでここに誘惑された人のために:はい、あなたはあなたの列挙型であなた自身のメソッドを定義することができます。そのような非静的メソッドを呼び出す方法を知りたい場合は、他の非静的メソッドと同じ方法で、そのメソッドを定義または継承する型のインスタンスで呼び出します。列挙型の場合、そのようなインスタンスは単にENUM_CONSTANTsです。

したがって、必要なのはEnumType.ENUM_CONSTANT.methodName(arguments)です。


問題から問題に戻りましょう。解決策の1つは

public enum Direction {

    NORTH, SOUTH, EAST, WEST;

    private Direction opposite;

    static {
        NORTH.opposite = SOUTH;
        SOUTH.opposite = NORTH;
        EAST.opposite = WEST;
        WEST.opposite = EAST;
    }

    public Direction getOppositeDirection() {
        return opposite;
    }

}

Direction.NORTH.getOppositeDirection()戻りDirection.SOUTHます。


@jedwardsコメントを説明するためのもう少し「ハッキー」な方法がありますが、フィールドを追加したり、それらの順序を変更するとコードが壊れるため、最初のアプローチほど柔軟ではありません。

public enum Direction {
    NORTH, EAST, SOUTH, WEST;

    // cached values to avoid recreating such array each time method is called
    private static final Direction[] VALUES = values();

    public Direction getOppositeDirection() {
        return VALUES[(ordinal() + 2) % 4]; 
    }
}

3
私は.values()[ordinal()]ハックを
作り上げよう

どうやって使うの?このテクニックは何と呼ばれていますか?
Thufir 2014

1
@Thufir「どのように使用するか」メソッドについて質問する場合は、他のメソッドと同様に、このメソッドを使用してクラスのインスタンスで呼び出します。インスタンスDirection列挙型クラスがありNORTHEASTSOUTHWESTあなただけ使用できるようにNORTH.getOppositeDirection()し、それが返されますSOUTH。「このテクニックは何と呼ばれていますか?」質問がある場合static{...}、それは静的初期化ブロックであり、クラスが最初にロードされたときに呼び出されるコードです(静的フィールドを初期化する同じプロセスの一部です)。
Pshemo 14

@Pshemo、静的ブロックに設定されている値をsayプロパティファイルから挿入する必要がある場合、上記のコードのSpringバージョンはどのようになるのでしょうか。
Vikas Prasad

162

このような小さな列挙型の場合、最も読みやすい解決策は次のとおりです。

public enum Direction {

    NORTH {
        @Override
        public Direction getOppositeDirection() {
            return SOUTH;
        }
    }, 
    SOUTH {
        @Override
        public Direction getOppositeDirection() {
            return NORTH;
        }
    },
    EAST {
        @Override
        public Direction getOppositeDirection() {
            return WEST;
        }
    },
    WEST {
        @Override
        public Direction getOppositeDirection() {
            return EAST;
        }
    };


    public abstract Direction getOppositeDirection();

}

8
いい案!これは、一般的に各列挙値に特定の動作を持たせたい場合にも適しています。
OferBr 2014年

28

これは機能します:

public enum Direction {
    NORTH, SOUTH, EAST, WEST;

    public Direction oppose() {
        switch(this) {
            case NORTH: return SOUTH;
            case SOUTH: return NORTH;
            case EAST:  return WEST;
            case WEST:  return EAST;
        }
        throw new RuntimeException("Case not implemented");
    }
}

8
nullを返すのではなく、適切なRuntimeExceptionをスローするデフォルト句は、新しく追加された方向の反対を定義しないことでプログラマエラーがあったことを示す方がよい場合があります。
Timothy055、2015年

1
これには、呼び出し側がnullを処理する必要があります。また、メンテナーは、新しい方向タイプが追加されるたびにケースを追加する必要があります。それぞれの列挙値によってオーバーライドできる抽象メソッドの使用に関するAmir Afghaniの回答を参照してください。これにより、値が欠落するリスクがなくなり、nullの処理について心配する必要がなくなります。
マイケルピーターソン

14

抽象メソッドを作成し、各列挙値でオーバーライドします。それを作成している間、あなたは反対を知っているので、それを動的に生成または作成する必要はありません。

ただし、読みやすくはありません。おそらくswitchより管理しやすいでしょうか?

public enum Direction {
    NORTH(1) {
        @Override
        public Direction getOppositeDirection() {
            return Direction.SOUTH;
        }
    },
    SOUTH(-1) {
        @Override
        public Direction getOppositeDirection() {
            return Direction.NORTH;
        }
    },
    EAST(-2) {
        @Override
        public Direction getOppositeDirection() {
            return Direction.WEST;
        }
    },
    WEST(2) {
        @Override
        public Direction getOppositeDirection() {
            return Direction.EAST;
        }
    };

    Direction(int code){
        this.code=code;
    }
    protected int code;

    public int getCode() {
        return this.code;
    }

    public abstract Direction getOppositeDirection();
}

4

はい、私たちはいつもそれをしています。新しいオブジェクトではなく静的インスタンスを返す

 static Direction getOppositeDirection(Direction d){
       Direction result = null;
       if (d != null){
           int newCode = -d.getCode();
           for (Direction direction : Direction.values()){
               if (d.getCode() == newCode){
                   result = direction;
               }
           }
       }
       return result;
 }

0
public enum Direction {
    NORTH, EAST, SOUTH, WEST;

    public Direction getOppositeDirection(){
        return Direction.values()[(this.ordinal() + 2) % 4];
    }
}

列挙型には、列挙された順序で列挙型のすべての値を含む配列を返す静的値メソッドがあります。ソース

NORTHは1、EASTは2、SOUTHは3、WESTは4を取得します。単純な方程式を作成して、反対の方程式を取得できます。

(値+ 2)%4


2
なぜこれが答えなのですか?これが将来の読者、またはそのことについての誰かが説明なしで学ぶのを助けることをどのように期待しますか?
GrumpyCrouton 2017年

このコードは質問に答えることがありますが、問題を解決する方法や理由に関する追加のコンテキストを提供することで、回答の長期的な価値が向上します。あなたが今尋ねている人だけでなく、あなたが将来の読者のための質問に答えていることを忘れないでください!回答を編集して説明を追加し、どの制限および前提が適用されるかを示してください。また、この回答が他の回答よりも適切である理由について言及しても問題ありません。
ItamarG3 2017年

コメントなしでコードを読むのは難しいですか?または、7行のコード専用のjavadocが必要ですか?
プレガントン2017年

1
このソリューションは、列挙値の順序に依存するため、脆弱です。順序をアルファベット順に変更すると、巧妙な方程式は正反対を提供しなくなります。
ジョシュJ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.