Java中枚举的实现与应用详解

 更新时间:2023年12月20日 10:14:03   作者:Brain_L  
这篇文章主要介绍了Java中枚举的实现与应用详解,EnumTest中还有一个VALUES数组,里面存储着所有的枚举实例,调用values方法时返回VALUES数组的clone,需要的朋友可以参考下

前言

Java的枚举和C/C++中的枚举作用上类似,实现上不一样。

本文主要探讨下Java中枚举的实现与应用。

如果要定义常量,可能会这样定义:private static final int SUCCESS = 0;一旦这样的定义多了之后,就很难管理,容易出错,甚至重复定义。用枚举的话就很简洁清晰。

枚举原理分析

public enum EnumTest {
    SUCCESS,
    FAILURE,
    EXCEPTION
}

enum是和class、interface同等级的关键字,那么它有什么特殊的地方呢?遇事不决看源码。。。反编译看下上面的代码

public final class EnumTest extends Enum
{
    public static EnumTest[] values()
    {
        return (EnumTest[])$VALUES.clone();
    }
    public static EnumTest valueOf(String s)
    {
        return (EnumTest)Enum.valueOf(com/brain/demo/enumtest/EnumTest, s);
    }
    private EnumTest(String s, int i)
    {
        super(s, i);
    }
    public static final EnumTest SUCCESS;
    public static final EnumTest FAILURE;
    public static final EnumTest EXCEPTION;
    private static final EnumTest $VALUES[];
    static 
    {
        SUCCESS = new EnumTest("SUCCESS", 0);
        FAILURE = new EnumTest("FAILURE", 1);
        EXCEPTION = new EnumTest("EXCEPTION", 2);
        $VALUES = (new EnumTest[] {
            SUCCESS, FAILURE, EXCEPTION
        });
    }
}

枚举里只有三行,结果反编译出来这么多东西。

enum其实就是实现了Enum的类,所以还是先看下Enum这个类。

public abstract class Enum<E extends Enum<E>>
        implements Comparable<E>, Serializable {
    private final String name;//枚举名称
    private final int ordinal;//序数,从0开始算
    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;
    }
    protected final Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException();
    }
}

两个主要属性,name和ordinal。结合EnumTest反编译的结果,初始化时会调用父类(Enum)的构造方法,将name和ordinal传进去,name是枚举的名称,ordinal是声明的顺序(从0开始)

EnumTest中还有一个VALUES数组,里面存储着所有的枚举实例,调用values方法时返回VALUES数组的clone。

调用valueOf方法时,会调用Enum的valueOf方法

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);
    }
//Class.java
Map<String, T> enumConstantDirectory() {
        if (enumConstantDirectory == null) {
            T[] universe = getEnumConstantsShared();
            if (universe == null)
                throw new IllegalArgumentException(
                    getName() + " is not an enum type");
            Map<String, T> m = new HashMap<>(2 * universe.length);
            for (T constant : universe)
                m.put(((Enum<?>)constant).name(), constant);
            enumConstantDirectory = m;
        }
        return enumConstantDirectory;
    }
T[] getEnumConstantsShared() {
        if (enumConstants == null) {
            if (!isEnum()) return null;
            try {
                final Method values = getMethod("values");
                java.security.AccessController.doPrivileged(
                    new java.security.PrivilegedAction<Void>() {
                        public Void run() {
                                values.setAccessible(true);
                                return null;
                            }
                        });
                @SuppressWarnings("unchecked")
                T[] temporaryConstants = (T[])values.invoke(null);
                enumConstants = temporaryConstants;
            }
            // These can happen when users concoct enum-like classes
            // that don't comply with the enum spec.
            catch (InvocationTargetException | NoSuchMethodException |
                   IllegalAccessException ex) { return null; }
        }
        return enumConstants;
    }

追着源码一层层调用,最后还是调用values方法,拿到包含所有枚举实例的数组。将枚举的name作为key,实例作为value放入map中。valueOf根据传入的name从map中取出对应的实例

枚举可以用来实现单例,并且是实现单例的最佳方式。关于为什么枚举是单例的最佳实现,参见另一篇博文——几种单例的对比。

枚举应用

除了枚举自身具备的两个属性name和ordinal外,还可以自定义需要的属性,自定义方法。

public enum EnumTest {
    SUCCESS(0, "调用成功"),
    FAILURE(1, "调用失败"),
    EXCEPTION(-1, "调用出错");
    private int status;
    private String msg;
    EnumTest(int status, String msg) {
        this.status = status;
        this.msg = msg;
    }
    public int getStatus() {
        return status;
    }
    public void setStatus(int status) {
        this.status = status;
    }
    public String getMsg() {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
    public String getDesc() {
        return status + ":" + msg;
    }
    public static void main(String[] args) {
        System.out.println(EnumTest.FAILURE.getDesc());//1:调用失败
    }
}

由于enum实际上是继承了Enum类,又由于java的单继承特性,不能再继承其他类,但是仍可以通过别的方式实现类似的功能。

public enum EnumTest {
    SUCCESS(0, "调用成功") {
        @Override
        String getDesc() {
            return "恭喜调用成功";
        }
    },
    FAILURE(1, "调用失败") {
        @Override
        String getDesc() {
            return "调用失败,请重试";
        }
    },
    EXCEPTION(-1, "调用出错") {
        @Override
        String getDesc() {
            return "调用出错";
        }
    };
    private int status;
    private String msg;
    EnumTest(int status, String msg) {
        this.status = status;
        this.msg = msg;
    }
    abstract String getDesc();
    public int getStatus() {
        return status;
    }
    public void setStatus(int status) {
        this.status = status;
    }
    public String getMsg() {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
}

或者干脆实现接口也可以达到同样的效果。

到此这篇关于Java中枚举的实现与应用详解的文章就介绍到这了,更多相关Java枚举内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 关于Java中配置ElasticSearch集群环境账号密码的问题

    关于Java中配置ElasticSearch集群环境账号密码的问题

    这篇文章主要介绍了Java中配置ElasticSearch集群环境账号密码的问题,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-04-04
  • Java函数式编程(二):集合的使用

    Java函数式编程(二):集合的使用

    这篇文章主要介绍了Java函数式编程(二):集合的使用,本文着重讲解了遍历列表的一些方法,需要的朋友可以参考下
    2014-09-09
  • 解读nacos获取配置文件的大致过程

    解读nacos获取配置文件的大致过程

    这篇文章主要介绍了nacos获取配置文件的大致过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-07-07
  • 在Java Web项目中添加定时任务的方法

    在Java Web项目中添加定时任务的方法

    在Java Web程序中加入定时任务,这里介绍两种方式使用监听器注入,使用Spring注解@Scheduled注入,需要的朋友可以参考下
    2018-01-01
  • SpringBoot 实现流控的操作方法

    SpringBoot 实现流控的操作方法

    本文介绍了限流算法的基本概念和常见的限流算法,包括计数器算法、漏桶算法和令牌桶算法,还介绍了如何在Spring Boot中使用Guava库和自定义注解以及AOP实现接口限流功能,感兴趣的朋友一起看看吧
    2024-12-12
  • @MapperScan和@ComponentScan一块使用导致冲突的解决

    @MapperScan和@ComponentScan一块使用导致冲突的解决

    这篇文章主要介绍了@MapperScan和@ComponentScan一块使用导致冲突的解决,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11
  • spring mvc使用@InitBinder标签对表单数据绑定的方法

    spring mvc使用@InitBinder标签对表单数据绑定的方法

    这篇文章主要介绍了spring mvc使用@InitBinder标签对表单数据绑定的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-03-03
  • mybatisplus添加真正的批量新增、批量更新的实现

    mybatisplus添加真正的批量新增、批量更新的实现

    这篇文章主要介绍了mybatisplus添加真正的批量新增、批量更新的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03
  • SpringBoot整合Freemarker实现页面静态化的详细步骤

    SpringBoot整合Freemarker实现页面静态化的详细步骤

    这篇文章主要介绍了SpringBoot整合Freemarker实现页面静态化,第一步要创建项目添加依赖,本文分步骤给大家详细讲解,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-10-10
  • 深入理解java中的null“类型”

    深入理解java中的null“类型”

    这篇文章主要介绍了深入理解java中的null“类型”,分享了相关代码示例,小编觉得还是挺不错的,具有一定借鉴价值,需要的朋友可以参考下
    2018-01-01

最新评论