Can enumerations contain methods?

Asked

Viewed 330 times

4

I don’t know if that’s the term, "abstract methods in a enum".

My doubt arose after seeing this implementation in code review. Until then I had never seen this kind of thing in any tutorial or article referring to enum in Java and found it sensational. Follows a passage:

public enum Choices {
   ROCK("rock") {
       @Override
       public List<Choices> getWinsAgainst() {
          if (winsAgainst.isEmpty()) {
              winsAgainst.add(SCISSORS);
              winsAgainst.add(LIZARD);
          }
          return winsAgainst;
       }
   }

   // restante do código
}
  1. An enumeration may have a method implemented within it?
  2. How access control to these methods works?
  3. When to use this practice? Implement directly on enum at the instead of having a class.

1 answer

4


In Java, an enumeration is nothing but that a class either inherits [implicitly] from Enum. The number of instances of it is fixed, and it may or may not be abstract - the important thing is that all its elements are concrete. That is, if it has abstract methods, then every element needs to have a body [that implements these methods]. Otherwise, they may or may not have.

  • An enumeration can have everything a class has, including fields and methods.

    public enum Planet {
        MERCURY (3.303e+23, 2.4397e6),
        VENUS   (4.869e+24, 6.0518e6),
        EARTH   (5.976e+24, 6.37814e6),
        MARS    (6.421e+23, 3.3972e6),
        JUPITER (1.9e+27,   7.1492e7),
        SATURN  (5.688e+26, 6.0268e7),
        URANUS  (8.686e+25, 2.5559e7),
        NEPTUNE (1.024e+26, 2.4746e7);
    
        private final double mass;   // in kilograms
        private final double radius; // in meters
        Planet(double mass, double radius) {
            this.mass = mass;
            this.radius = radius;
        }
        private double mass() { return mass; }
        private double radius() { return radius; }
    
        // universal gravitational constant  (m3 kg-1 s-2)
        public static final double G = 6.67300E-11;
    
        double surfaceGravity() {
            return G * mass / (radius * radius);
        }
        double surfaceWeight(double otherMass) {
            return otherMass * surfaceGravity();
        }
        public static void main(String[] args) {
            if (args.length != 1) {
                System.err.println("Usage: java Planet <earth_weight>");
                System.exit(-1);
            }
            double earthWeight = Double.parseDouble(args[0]);
            double mass = earthWeight/EARTH.surfaceGravity();
            for (Planet p : Planet.values())
               System.out.printf("Your weight on %s is %f%n",
                                 p, p.surfaceWeight(mass));
        }
    }
    

    Source.

    The access control to these methods is the same as that of any class (public, private, protected...). Except for the constructor, which needs to be "default" - i.e. without any modifier - or private, since you cannot call it directly to create new instances of enum.

  • An enumeration may have abstract methods in its definition (i.e. the "normal" part of the code); however, each of its elements needs to implement these methods, as each of them is a concrete class and final:

    public enum Choices {
       ROCK("rock") {
           public List<Choices> getWinsAgainst() { ... }
       },
       PAPER("paper") { ... },       // Precisa implementar getWinsAgainst
       SCISSORS("scissors") { ... }; // Precisa implementar getWinsAgainst
       SPOCK("Spock") { ... },       // Precisa implementar getWinsAgainst
       LIZARD("lizard") { ... },     // Precisa implementar getWinsAgainst
    
       private String nome;
       Choices(String nome) {
           this.nome = nome;
       }
    
       public abstract List<Choices> getWinsAgainst(); // todos os elementos
                                                       // precisam implementar
    }
    
  • Moreover, every enumeration inherits implicitly from Enum (i.e. cannot inherit from any other class, but can implement interfaces normally). It has, if I’m not mistaken, a generic type just like the type itself, ex.: enum X extends Enum<X>, also implicitly established. Every element that has a body has its own class, and it is the only object of it (i.e. Singleton). One cannot inherit from the class of these elements (i.e. are final), nor of the enum. Nor can new instances of enum (i.e. is in fact abstract - although elements without body are instances of it).

On when to use, I would say that only in cases where the number of instances is finite, known at compile time, and unlikely to change in the future. I have difficulty thinking of examples, but think of "natural" sets like the cardinal points (north, south, east, west) or conventions that will hardly be replaced in the future, such as the days of the week (Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday). Personally, I see little use in enums (except for the possibility of using it in a switch, which is not very OO anyway), but someone with more practical experience in Java can know more use cases.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.