Enum source code analysis of Java enumeration class

I. Overview

Enumeration type is a very important reference type introduced after JDK 5, which can be used to define a series of enumeration constants.

Before the introduction of the enum keyword, to represent enumerable variables, only public static final can be used.

public staic final int SPRING = 1;
public staic final int SUMMER = 2;
public staic final int AUTUMN = 3;
public staic final int WINTER = 4;

This implementation has several drawbacks. First, it's type unsafe. Imagine that there is a method that expects to accept a season as a parameter, so the parameter type can only be declared as int, but the value passed in may be 99. Obviously, the reasonableness of the parameters can only be judged at runtime, and the check cannot be completed during compilation. Secondly, the meaning is not strong and the meaning is not clear. We use an enumeration, and the string character representation of the enumeration is used in many occasions, and in the above implementation, only one number can be obtained, and the meaning of the enumeration constant cannot be expressed intuitively. Of course String constants can also be used, but there will be performance problems because the comparison depends on the string comparison operation.

Using enum to represent enumeration can better guarantee the type safety and readability of the program.

enum s are type safe. Except for predefined enum constants, no other values ​​can be assigned to enum variables. This is very different from enums implemented with int or String.

enum has its own namespace and is highly readable. When creating an enum, the compiler automatically adds some useful features. Each enum instance has a name (name) and an ordinal (ordinal), and the string representation of the enum instance can be obtained through the toString() method. It is also possible to obtain an array of enum constants in order through the values() method.

There is also a particularly useful feature of enum, which can be used in switch statements, which is also the most commonly used way of enum.

2. Source code analysis

public abstract class Enum<E extends Enum<E>>
        implements Comparable<E>, Serializable {

    //the name of the enum constant
	//Most programmers should use the toString method instead of accessing this field.
    private final String name;

    //Returns the name of this enum constant, exactly as declared in its enum declaration
    public final String name() {
        return name;
    }

    //the ordinal of this enum constant (its position in the enum declaration where the ordinal of the initial constant is zero)
    private final int ordinal;

    //return serial number
    public final int ordinal() {
        return ordinal;
    }

    // Constructor
    protected Enum(String name, int ordinal) {
        this.name = name;
        this.ordinal = ordinal;
    }

    //Returns the name of this enum constant contained in the declaration
    public String toString() {
        return name;
    }

    //Returns true if the specified object is equal to this enum constant.
    public final boolean equals(Object other) {
        return this==other;
    }

    public final int hashCode() {
        return super.hashCode();
    }

    // cannot be cloned
    protected final Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException();
    }

    //Compares this enumeration with the specified enumeration ordinal
    public final int compareTo(E o) {
        Enum<?> other = (Enum<?>)o;
        Enum<E> self = this;
        if (self.getClass() != other.getClass() && // optimization
                self.getDeclaringClass() != other.getDeclaringClass())
            throw new ClassCastException();
        return self.ordinal - other.ordinal;
    }

    //Returns the Class object corresponding to the enum type of this enum constant
    @SuppressWarnings("unchecked")
    public final Class<E> getDeclaringClass() {
        Class<?> clazz = getClass();
        Class<?> zuper = clazz.getSuperclass();
        return (zuper == java.lang.Enum.class) ? (Class<E>)clazz : (Class<E>)zuper;
    }

    /**
     * Returns the enum constant of the specified enum type with the specified name.
     * The name must exactly match the identifier used to declare an enum constant of this type.
     * Note that for a specific enum type T,
     *  There are two implicitly declared methods that can be used directly:
     *      public static T valueOf(String)    Get a single enum type by name
     *      public static T[] values()   Get an array of all enumeration types
     */
    public static <T extends 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);
    }

    //An enum class cannot have a finalize method
    protected final void finalize() { }

    //prevent deserialization
    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");
    }
}

case

example 1

@Getter
public enum DelFlagEnum {

    NO(0, "not deleted"),
    YES(1, "deleted"),;

    Integer code;
    String name;

    DelFlagEnum(Integer code, String name) {
        this.code = code;
        this.name = name;
    }

    public static DelFlagEnum getCode(Integer code) {
        for (DelFlagEnum value : DelFlagEnum.values()) {
            if(value.getCode().equals(code)) {
                return value;
            }
        }
        return null;
    }
}

Example 2

@Getter
public enum InsuranceIndustry {
    INSURANCE_AGENT("1010", "insurance agent"),
    INSURANCE_BROKER("1011", "insurance broker"),
    INSURANCE_ADJUSTMENT("1012", "Insurance Adjustment"),
    PROPERTY_INSURANCE("1013", "property insurance company"),
    LIFE_INSURANCE("1014", "life insurance company"),
    HEALTH_INSURANCE("1015", "Health insurance"),
    ENDOWMENT_INSURANCE("1016", "Pension"),
    ;
    String code;
    String name;

    InsuranceIndustry(String code, String name) {
        this.code = code;
        this.name = name;
    }

    // cache data in map
    private static final Map<String, String> map = new HashMap<>();

    static {
        for (InsuranceIndustry insurance : InsuranceIndustry.values()) {
            map.put(insurance.getCode(), insurance.getName());
        }
    }

    // Query value based on name
    public static String getNameByCode(String code) {
        return map.get(code);
    }
}

expand

1. How enums are thread-safe

Static resources are initialized when a Java class is actually used for the first time, and the Java class loading and initialization process is thread-safe. So, creating an enum type is thread-safe.

2. Why singletons implemented with enums are the best way

  1. Enumeration is simple to write
  2. The enum handles the serialization itself
  3. Enum instance creation is thread-safe

Reference article

Tags: Java

Posted by Amgine on Mon, 23 May 2022 20:14:04 +0300