81

I have an enum, which looks like

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

and I want to do something like

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

I simplified the example for didactic purposes, but this would be really useful to me for my real life example. Can I do it in Java?

4 Answers 4

112

Yes Enum is a class in 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; }
}

but in your case for a real system I would make that an Enum as well since there is a fixed set of types of animals.

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

Also note that it is important to make any instance variable final as well.

You can find more details about it in the Java Language Specification.

Sign up to request clarification or add additional context in comments.

6 Comments

what if I want different categories, like mammal, amphibian, reptile?
you would need multiple boolean flags for each one, or you could make that category and Enum as well as I suggest in my solution.
not methods, CONSTRUCTORS you should not be able to create an instance of an Enum outside itself. Making the CONSTRUCTOR private means only the static instances on itself can create instances.
explicit is always better than implicit
Why is it important to declare its instance variables as final?
|
32

I have an other option:

public enum Animal {
    ELEPHANT {
        @Override
        boolean isMammal() {
            return true;
        };
        @Override
        boolean isReptile() {
            return false;
        }
    },
    SNAKE {
        @Override
        boolean isMammal() {
            return false;
        };
        @Override
        boolean isReptile() {
            return true;
        }
    };

    abstract boolean isMammal();
    abstract boolean isReptile();
}

No need of external Interface and I am quite sure (did not test) it works also on Java7.

1 Comment

This is the most complete answer! +1
16

Yes, you can. It would look like this:

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

Then you would call it like:

Animal.ELEPHANT.isAmphibian()

6 Comments

constructors to Enums should be private
Not "should be private", but must be private.
That's strange - the Planet example at java.sun.com/j2se/1.5.0/docs/guide/language/enums.html doesn't use the private modifier on the constructor. Are you sure?
Not needed. They're implicitly already private. Enumns are uninstantiable at any way.
No, not private. package private. Or so I believe...?
|
8

As well as using the techniques above which add a field to the enumerated type you can also use a pure method based approach and polymorphism. This is more "OOP style" but I would not say it is necessarily better.

Unfortunately, you may (see the comment below) need to define an interface:

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

But then you can them implement the interface in each of your enumeration elements:

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

Note that I use default implementations in the interface to cut down on the amount of typing you need in the enum.

Regarding the necessity of the interface: I tried adding the methods in the interface as abstract methods at the top of the enum and Eclipse seemed to allow it and insisted on implementations in the enum elements, but then failed to compile those properly. So it looks like it ought to be possible without an interface, but perhaps it is not yet implemented in the compiler.

1 Comment

Actually you don't need to create an Interface and neither need Java8. See my answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.