web-dev-qa-db-ja.com

Java Enumのジェネリック型としてのEnum

引数として自分のEnumを取る抽象クラスで抽象メソッドを作成しようとしています。しかし、Enumがジェネリックになることも必要です。

だから私はそれをそのように宣言しました:

public abstract <T extends Enum<T>> void test(Enum<T> command);

実装では、その1つとして列挙型があります。

public enum PerspectiveCommands {
    PERSPECTIVE
}

メソッド宣言は次のようになります。

@Override
public <PerspectiveCommands extends Enum<PerspectiveCommands>> void test(Enum<PerspectiveCommands> command) {

}

しかし、私がそうするなら:

@Override
public <PerspectiveCommands extends Enum<PerspectiveCommands>> void test(Enum<PerspectiveCommands> command) {
    if(command == PerspectiveCommands.PERSPECTIVE){
        //do something
    }
}

エラーが発生したPerspectiveCommands.PERSPECTIVEにアクセスできません:

cannot find symbol symbol: variable PERSPECTIVE   location: class Enum<PerspectiveCommands> where PerspectiveCommands is a type-variable: PerspectiveCommands extends Enum<PerspectiveCommands> declared in method <PerspectiveCommands>test(Enum<PerspectiveCommands>)

私はこのような回避策を講じました:

public <T extends Enum<T>> byte[] executeCommand(Enum<T> command) throws Exception{
    return executeCommand(command.name());
}

@Override
protected byte[] executeCommand(String e) throws Exception{
    switch(PerspectiveCommands.valueOf(e)){
        case PERSPECTIVE:
            return executeCommand(getPerspectiveCommandArray());
        default:
            return null;
    }
}

しかし、私の回避策を通過しない可能性があるかどうかを知りたいですか?

24
Garcia Julien

メソッド実装では、PerspectiveCommandsは列挙型ではなく、多くの場合Tと呼ばれる型パラメーターです。したがって、すでに述べたaxtavtのように同じ名前の列挙型を隠しているため、PERSPECTIVEはここでは不明です。

抽象メソッドの宣言は問題ありませんが、少し異なるアプローチを使用できます。

このメソッドは汎用バージョンをオーバーライドしないため、public void test(PerspectiveCommands command)は機能しません。その理由は、ジェネリックバージョンでは型がパラメーターから推測されるため、任意の列挙型を渡すことができるためです。

ただし、抽象メソッドを定義するインターフェイスまたは抽象クラスがあると思います。次のようなものを試してください:

interface TestInterface<T extends Enum<T>>
{
  public abstract void test(T command);
}

class TestImpl implements TestInterface<PerspectiveCommands>
{
  @Override
  public void test(PerspectiveCommands command) {
    if(command == PerspectiveCommands.PERSPECTIVE){
        //do something
    }
  }
}
27
Thomas

@mikeの答えが道です。

public interface Command1 {
}

public enum MyCommand1 implements Command1 {
}

abstract <E extends Enum<E> & Command1> void execute(E command);

ここに別のバージョンがあります

// intending to be used only on enums
public interface Command2<E extends Enum<E>> extends Command1 {
}

public enum MyCommand2 implements Command2<MyCommand2> {
}

abstract <E extends Enum<E> & Command2<E>> execute(E command);
7
Jin Kwon

@axtavtが既に指摘したように、問題はシャドウイングです。

コードをそのまま動作させたい場合は、型変数の名前を変更してシャドーイングを削除できます。

public <C extends Enum<C>> void test(Enum<C> command)

また、すべての列挙型派生クラスのインスタンスではなく、コマンド列挙型のみを許可するために、型境界にインターフェイスを追加します。

public <C extends Enum<C> & CommandInterface> void test(Enum<C> command)
6
mike