【Java原理系列】 Enum枚举的原理源码详解

Java Enum枚举的原理源码详解

基本原理

在 Java 中,enum 是一种特殊的数据类型,用于定义枚举类型。enum 关键字在编译时会被编译器转换为一个继承自 java.lang.Enum 的类,并在类加载时创建并初始化枚举常量。枚举常量是该枚举类的静态 final 实例,可以通过枚举常量名称访问,并且可以定义自己的方法和属性。

使用示例

enum Color {
    RED, GREEN, BLUE;
    
    public void printColor() {
        System.out.println(this.name());
    }
}

public class EnumExample {
    public static void main(String[] args) {
        Color color = Color.RED;
        
        System.out.println(color); // 输出 RED
        
        color.printColor(); // 输出 RED
    }
}

在上述示例中,Color 是一个枚举类型,包含了三个枚举常量:REDGREENBLUE。这些枚举常量实际上是 Color 类的静态 final 实例,它们在类加载时被创建并初始化。

EnumExample 类的 main() 方法中,我们创建了一个 Color 类型的变量 color,并将其赋值为 Color.RED。可以直接打印 color 变量,得到的输出是 RED,这是因为枚举常量的 toString() 方法默认返回常量名称。

另外,枚举类型也可以定义自己的方法,如上述示例中的 printColor() 方法。在调用 color.printColor() 时,输出的结果同样是 RED,这是因为 name() 方法返回了枚举常量的名称。

方法总结

Enum类是所有Java语言枚举类型的通用基类。枚举类型是一种特殊的数据类型,用于定义一组固定的常量值。

以下是Enum类的主要方法和功能:

  • name():返回枚举常量的名称,与在枚举声明中声明的名称相同。
  • ordinal():返回枚举常量的序号,即在枚举声明中的位置,初始常量的序号为0。
  • toString():返回枚举常量的名称,通常用于以字符串形式表示枚举常量。
  • equals(Object other):比较枚举常量是否与指定对象相等。
  • hashCode():返回枚举常量的哈希码。
  • compareTo(E o):比较枚举常量的顺序,根据枚举常量在声明中的顺序进行比较。
  • getDeclaringClass():返回枚举常量所属的枚举类型的Class对象。
  • valueOf(Class<T> enumType, String name):根据指定的枚举类型和名称,返回对应的枚举常量。

此外,Enum类还包含一些其他的保护方法,如clone()finalize()和反序列化相关的方法。

需要注意的是,枚举类型在编译时会由编译器自动生成一些方法,如values()valueOf(String)方法,用于获取枚举类型的所有常量和根据名称获取对应的枚举常量。

枚举类型在Java中常用于表示一组固定的常量值,例如表示星期几、表示颜色等。枚举类型具有类型安全性和可读性高的特点,可以提高代码的可维护性和可读性。

中文源码

/**
 * 这是所有Java语言枚举类型的通用基类。
 *
 * 更多关于枚举的信息,包括编译器自动生成的隐式声明方法的描述,
 * 可以在《Java™语言规范》第8.9节中找到。
 *
 * <p>注意,在将枚举类型用作集合的类型或映射中的键的类型时,
 * 可以使用专门和高效的{@linkplain java.util.EnumSet set}和{@linkplain
 * java.util.EnumMap map}实现。
 *
 * @param <E> 枚举类型的子类
 * @see     Class#getEnumConstants()
 * @see     java.util.EnumSet
 * @see     java.util.EnumMap
 * @since   1.5
 */
public abstract class Enum<E extends Enum<E>>
        implements Comparable<E>, Serializable {
    /**
     * 此枚举常量在枚举声明中声明时的名称。
     * 大多数程序员应该使用{@link #toString}方法而不是直接访问此字段。
     */
    private final String name;

    /**
     * 返回此枚举常量的名称,与其枚举声明中的名称完全相同。
     *
     * <b>大多数程序员应该优先使用{@link #toString}方法,
     * 因为toString方法可能返回更友好的名称。</b>
     * 此方法主要设计用于某些特殊情况下需要确切名称的情况,
     * 该名称不会因发布而变化。
     *
     * @return 此枚举常量的名称
     */
    public final String name() {
        return name;
    }

    /**
     * 此枚举常量的序号(它在枚举声明中的位置,初始常量的序号为零)。
     *
     * 大多数程序员不会使用此字段。它主要用于高级基于枚举的数据结构,
     * 如{@link java.util.EnumSet}和{@link java.util.EnumMap}。
     */
    private final int ordinal;

    /**
     * 返回此枚举常量的序号(它在枚举声明中的位置,初始常量的序号为零)。
     *
     * 大多数程序员不会使用此方法。它主要用于高级基于枚举的数据结构,
     * 如{@link java.util.EnumSet}和{@link java.util.EnumMap}。
     *
     * @return 此枚举常量的序号
     */
    public final int ordinal() {
        return ordinal;
    }

    /**
     * 唯一构造方法,程序员无法调用此构造方法,它是编译器根据枚举类型声明生成的代码使用的。
     *
     * @param name - 枚举常量的名称,即其用于声明的标识符。
     * @param ordinal - 枚举常量的序号(它在枚举声明中的位置,初始常量的序号为零)。
     */
    protected Enum(String name, int ordinal) {
        this.name = name;
        this.ordinal = ordinal;
    }

    /**
     * 返回包含在声明中的此枚举常量的名称。
     * 此方法可以被重写,但通常不需要或不希望这样做。
     * 当存在更“程序员友好”的字符串形式时,枚举类型应该重写此方法。
     *
     * @return 此枚举常量的名称
     */
    public String toString() {
        return name;
    }

    /**
     * 如果指定对象等于此枚举常量,则返回true。
     *
     * @param other - 与此对象进行比较是否相等的对象。
     * @return 如果指定对象等于此枚举常量,则返回true。
     */
    public final boolean equals(Object other) {
        return this==other;
    }

    /**
     * 返回此枚举常量的哈希码。
     *
     * @return 此枚举常量的哈希码。
     */
    public final int hashCode() {
        return super.hashCode();
    }

    /**
     * 抛出CloneNotSupportedException异常。这样可以保证枚举常量不会被克隆,以维护它们的“单例”状态。
     *
     * @return (永远不返回)
     */
    protected final Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException();
    }

    /**
     * 将此枚举与指定对象进行比较以确定顺序。如果此对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。
     *
     * 枚举常量只能与同一枚举类型的其他枚举常量进行比较。此方法实现的自然顺序是声明常量的顺序。
     */
    public final int compareTo(E o) {
        Enum<?> other = (Enum<?>)o;
        Enum<E> self = this;
        if (self.getClass() != other.getClass() && // 优化
            self.getDeclaringClass() != other.getDeclaringClass())
            throw new ClassCastException();
        return self.ordinal - other.ordinal;
    }

    /**
     * 返回与此枚举常量的枚举类型相对应的Class对象。
     * 如果且仅当e1.getDeclaringClass() == e2.getDeclaringClass()时,
     * 两个枚举常量e1和e2才属于同一枚举类型。
     * (此方法返回的值可能与具有常量特定类体的枚举常量返回的值不同。)
     *
     * @return 与此枚举常量的枚举类型相对应的Class对象
     */
    @SuppressWarnings("unchecked")
    public final Class<E> getDeclaringClass() {
        Class<?> clazz = getClass();
        Class<?> zuper = clazz.getSuperclass();
        return (zuper == Enum.class) ? (Class<E>)clazz : (Class<E>)zuper;
    }

    /**
     * 返回指定枚举类型和名称对应的枚举常量。
     * 名称必须与该类型中用于声明枚举常量的标识符完全匹配(不允许存在多余的空白字符)。
     *
     * <p>注意,在特定枚举类型{@code T}的情况下,
     * 可以使用该枚举上隐式声明的{@code public static T valueOf(String)}方法
     * 将名称映射到相应的枚举常量,而不是使用此方法。
     * 可以通过调用该类型的隐式{@code public static T[] values()}方法获取该类型的所有常量。
     *
     * @param <T> 要返回其常量的枚举类型
     * @param enumType 要从中返回常量的枚举类型的{@code Class}对象
     * @param name 要返回的常量的名称
     * @return 指定枚举类型和名称对应的枚举常量
     * @throws IllegalArgumentException 如果指定的枚举类型没有具有指定名称的常量,
     *         或者指定的类对象不表示枚举类型
     * @throws NullPointerException 如果{@code enumType}或{@code name}为null
     * @since 1.5
     */
    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);
    }

    /**
     * 枚举类不能有finalize方法。
     */
    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");
    } 
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BigDataMLApplication

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值