Deep understanding of Java enumeration mechanism

Posted by rjs on Thu, 10 Feb 2022 00:41:37 +0100

Before reading this article, you need to understand how to define enumeration and its simple use

enumeration

1, How the JVM handles enumerations

  • A simple enumeration class

    public enum Fruit{
        APPLE(67),ORANGE(68),BANANA(69);
        int code;
    
        Fruit(int code){
            this.code=code;
        }
    }
    
  • Decompile fruit. Using the Jad command Class file, you can get the following contents:

    public final class Fruit extends Enum
    {
    
        public static Fruit[] values()
        {
            return (Fruit[])$VALUES.clone();
        }
    
        public static Fruit valueOf(String s)
        {
            return (Fruit)Enum.valueOf(Fruit, s);
        }
    
        private Fruit(String s, int i, int j)
        {
            super(s, i);
            code = j;
        }
    
        public static final Fruit APPLE;
        public static final Fruit ORANGE;
        public static final Fruit BANANA;
        int code;
        private static final Fruit $VALUES[];
    
        static
        {
            APPLE = new Fruit("APPLE", 0, 67);
            ORANGE = new Fruit("ORANGE", 1, 68);
            BANANA = new Fruit("BANANA", 2, 69);
            $VALUES = (new Fruit[] {
                APPLE, ORANGE, BANANA
            });
        }
    }
    
  • By enumerating the contents of the JVM, you can get:

    • Define a Fruit class inherited from Enum class. The Fruit class is decorated with final
    • Create a class object corresponding to each enumerated instance. These class objects are decorated with public static final, and generate an array to save all class objects
    • Generate a static code block for initializing class objects and class object arrays
    • Generate a constructor, which contains custom parameters and two default parameters (these two default parameters will be explained below)
      • This constructor is private by default and ensures that the enumeration is singleton
    • Generate a static values() method to return all class objects and an array of class objects
    • Generate a static valueOf() method, call the valueOf() method of the parent class, and return the corresponding class instance according to the parameter name (this method will be explained below)

2, Introduction to Enum class

The source code of Enum class is as follows:

public abstract class Enum<E extends java.lang.Enum<E>>
        implements Comparable<E>, Serializable {
    
    private final String name; 
    private final int ordinal; 
    
    public final String name() {
        return name;
    }
    
    public final int ordinal() {
        return ordinal;
    }
    
    protected Enum(String name, int ordinal) {
        this.name = name;
        this.ordinal = ordinal;
    }
    
    public String toString() {
        return name;
    }
    
    public final boolean equals(Object other) {
        return this == other;
    }
    
    public final int hashCode() {
        return super.hashCode();
    }
    
    protected final Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException();
    }

    public final int compareTo(E o) {
        java.lang.Enum other = (java.lang.Enum) o;
        java.lang.Enum self = this;
        if (self.getClass() != other.getClass() && // optimization
                self.getDeclaringClass() != other.getDeclaringClass())
            throw new ClassCastException();
        return self.ordinal - other.ordinal;
    }

    public final Class<E> getDeclaringClass() {
        Class clazz = getClass();
        Class zuper = clazz.getSuperclass();
        return (zuper == java.lang.Enum.class) ? clazz : zuper;
    }

    public static <T extends java.lang.Enum<T>> T valueOf(Class<T> enumType,
                                                          String name) {
        T result = enumType.enumConstantDirectory().get(name);
        if (result != null)
            return result;
        if (name == null)
            throw new NullPointerException("Name is null");
        throw new IllegalArgumentException(
                "No enum constant " + enumType.getCanonicalName() + "." + name);
    }

    protected final void finalize() {
    }

    private void readObject(ObjectInputStream in) throws IOException,
            ClassNotFoundException {
        throw new InvalidObjectException("can't deserialize enum");
    }

    private void readObjectNoData() throws ObjectStreamException {
        throw new InvalidObjectException("can't deserialize enum");
    }
}

By observing the above source code, we can get the characteristics of Enum class:

  • The Enum class has two member variables: name and ordinal
    • Name is used to record the name of enumeration constants, such as APPLE, ORANGE and BANANA
    • ordinal is used to record the order of enumeration constants when declared (starting from 0). For example, APPLE is 0, ORANGE is 1 and BANANA is 2
  • Enum class has a constructor, which has two input parameters, which assign values to name and ordinanl respectively
    • There is a constructor in the custom enumeration, which calls the constructor of the parent class Enum, and the static code block in the custom enumeration assigns values to these two attributes of the parent class
  • Enum class overrides the toString() method to return the name value of enumeration constant
  • The Enum class overrides the equals() method and compares directly with the equal sign
  • Enum class does not allow cloning, and the clone() method directly throws an exception (ensure that the enumeration is always singleton)
  • Enum class implements the Comparable interface to directly compare the ordinal value of the enumeration constant
  • Enum class has a static valueOf() method, which can return the corresponding enumeration constant according to the enumeration type and name
    • This method is called by the valueOf() method in the custom enumeration
  • Enum class does not allow deserialization, in order to ensure that the enumeration is always singleton

3, Some problems on enumeration

  1. Are custom enumerations allowed to inherit classes?

    A: enumeration does not allow inherited classes. The Jvm has inherited Enum class when generating enumeration. Since the Java language is single inheritance, it does not support inheriting additional classes (the only inheritance quota is used by the Jvm)

  2. Are custom enumerations allowed to implement interfaces?

    A: enumeration allows the implementation of interfaces. Because enumeration itself is a class, which can implement multiple interfaces

  3. Can enumerations be compared with equal signs?

    A: enumeration can be used for comparison. The Jvm will generate a class object for each enumerated instance. This class object is decorated with public static final and initialized in the static code block. It is a singleton

  4. Can custom classes inherit enumerations?

    A: enumeration cannot be inherited. Because when the Jvm generates the enumeration class, it declares it as final

  5. Can enumeration implement singleton mode?

    A: enumeration itself is a form friendly to singleton design pattern. It is a good way to implement singleton pattern

  6. When comparing enumerations using compareTo(), what is compared?

    Answer: the compareTo() method of the enumeration type compares the ordinal value of the enumeration class object

  7. When using equals() to compare enumerations, what is compared?

    Answer: the equals() method of the enumeration type compares the memory address of the enumeration class object, which is equivalent to the equal sign

Topics: Java JDK jvm Design Pattern