web-dev-qa-db-fra.com

Java Enum comme type générique dans Enum

J'essaie de créer une méthode abstraite dans une classe abstraite qui prend mon propre Enum comme argument. Mais je veux aussi que cet Enum soit générique.

Alors je l'ai déclaré comme ça:

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

Dans l'implémentation, j'ai enum comme celui-ci:

public enum PerspectiveCommands {
    PERSPECTIVE
}

et la déclaration de méthode devient:

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

}

Mais si je le fais:

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

Je n'ai pas accès au PerspectiveCommands.PERSPECTIVE avec l'erreur:

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>)

J'ai fait une solution de contournement comme celle-ci:

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;
    }
}

Mais je voudrais savoir s'il est possible de ne pas passer par ma solution?

24
Garcia Julien

Dans votre implémentation de méthode, PerspectiveCommands n'est pas l'énumération mais votre paramètre de type, souvent appelé T. Il masque ainsi l'énum du même nom comme l'a déjà dit axtavt, donc PERSPECTIVE est inconnu ici.

Votre déclaration de méthode abstraite est correcte mais vous pouvez utiliser une approche légèrement différente.

public void test(PerspectiveCommands command) ne fonctionnerait pas, car cette méthode ne remplacerait pas la version générique. La raison en est qu'avec la version générique, le type est déduit du paramètre et vous pouvez donc passer n'importe quelle énumération.

Cependant, je suppose que vous avez une interface ou une classe abstraite qui définit la méthode abstraite. Essayez donc quelque chose comme ceci:

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

La réponse de @ mike est la voie à suivre.

public interface Command1 {
}

public enum MyCommand1 implements Command1 {
}

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

Voici une autre version

// 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

Comme @axtavt l'a déjà souligné, le problème est l'observation.

Si vous souhaitez que votre code fonctionne tel quel, vous pouvez modifier le nom de la variable de type pour supprimer l'observation.

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

J'ajouterais également une interface à la limite de type pour autoriser uniquement les énumérations de commandes et non une instance de chaque classe dérivée d'énumérations.

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