web-dev-qa-db-fra.com

Puis-je ajouter une fonction aux énumérations en Java?

J'ai un enum qui ressemble à

public enum Animal {
  ELEPHANT,
  GIRAFFE,
  TURTLE,
  SNAKE,
  FROG
}

et je veux faire quelque chose comme

Animal frog = Animal.FROG;
Animal snake = Animal.SNAKE;

boolean isFrogAmphibian = frog.isAmphibian(); //true
boolean isSnakeAmphibian = snake.isAmphibian(); //false

boolean isFrogReptile = frog.isReptile(); //false
boolean isSnakeReptile = snake.isReptile(); //true

boolean isFrogMammal = frog.isMammal(); //false
boolean isSnakeMammal = snake.isMammal(); //false

J'ai simplifié l'exemple à des fins didactiques, mais cela me serait vraiment utile pour mon exemple réel. Puis-je le faire en Java?

58
Samuel Carrijo

Oui, Enum est une classe en Java:

public enum Animal 
{
  ELEPHANT(true),
  GIRAFFE(true),
  TURTLE(false),
  SNAKE(false),
  FROG(false);

  private final boolean mammal; 
  private Animal(final boolean mammal) { this.mammal = mammal; }
  public boolean isMammal() { return this.mammal; }
}

mais dans votre cas, pour un système réel, je ferais aussi un Enum puisqu'il existe un ensemble fixe de types d'animaux.

public enum Type
{
  AMPHIBIAN,
  MAMMAL,
  REPTILE,
  BIRD
}

public enum Animal 
{
  ELEPHANT(Type.MAMMAL),
  GIRAFFE(Type.MAMMAL),
  TURTLE(Type.REPTILE),
  SNAKE(Type.REPTILE),
  FROG(Type.AMPHIBIAN);

  private final Type type; 
  private Animal(final Type type) { this.type = type; }
  public boolean isMammal() { return this.type == Type.MAMMAL; }
  public boolean isAmphibian() { return this.type == Type.AMPHIBIAN; }
  public boolean isReptile() { return this.type == Type.REPTILE; }
  // etc...
}

Notez également qu'il est important de définir également toute variable d'instance final.

77
user177800

Oui, vous pouvez. Cela ressemblerait à ceci:

public enum Animal {
  ELEPHANT(false),
  GIRAFFE(false),
  TURTLE(false),
  SNAKE(false),
  FROG(true);

  private final boolean isAmphibian;

  Animal(boolean isAmphibian) {
    this.isAmphibian = isAmphibian;
  }

  public boolean isAmphibian() {
    return this.isAmphibian;
  }
}

Alors tu l'appellerais comme:

Animal.ELEPHANT.isAmphibian()

15
danben

En plus d'utiliser les techniques ci-dessus qui ajoutent un champ au type énuméré, vous pouvez également utiliser une approche basée sur une méthode pure et un polymorphisme. C'est plus du "style POO" mais je ne dirais pas que c'est nécessairement mieux.

Malheureusement, vous devez définir une interface:

public interface AnimalTraits {
    default boolean isAmphibian()   { return false; };
    default boolean isReptile()     { return false; };
    default boolean isMammal()      { return false; };
}

Mais vous pouvez ensuite les implémenter dans chacun de vos éléments d’énumération:

public enum Animal implements AnimalTraits {

     ELEPHANT   { @Override public boolean isMammal()    { return true; } },
     GIRAFFE    { @Override public boolean isMammal()    { return true; } },
     TURTLE     { @Override public boolean isReptile()   { return true; } },
     SNAKE      { @Override public boolean isReptile()   { return true; } },
     FROG       { @Override public boolean isAmphibian() { return true; } }
}

Notez que j’utilise les implémentations par défaut dans l’interface pour réduire la quantité de frappe dont vous avez besoin dans l’énumération.

Concernant la nécessité de l’interface: j’ai essayé d’ajouter des méthodes dans l’interface en tant que méthodes abstraites au sommet de l’énum et Eclipse a semblé le permettre et a insisté sur les implémentations dans les éléments enum, mais j’ai échoué à les compiler correctement. Il semble donc que cela devrait être possible sans interface, mais peut-être n'est-il pas encore implémenté dans le compilateur.

Remarque: nécessite Java 8 ou supérieur.

1
rghome