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枚举内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • JavaWeb中的文件的上传和下载

    JavaWeb中的文件的上传和下载

    JavaWeb 文件的上传和下载是指在Web应用中实现用户上传文件到服务器和从服务器下载文件的功能,通过JavaWeb技术,可以方便地实现文件的上传和下载操作,提供更好的用户体验和数据交互,需要的朋友可以参考下
    2023-10-10
  • jackson反序列化时如何忽略不需要的字段

    jackson反序列化时如何忽略不需要的字段

    这篇文章主要介绍了jackson反序列化时如何忽略不需要的字段,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • Mybatis-plus更新字段为null两种常用方法及优化

    Mybatis-plus更新字段为null两种常用方法及优化

    Mybatis Plus在进行更新操作时,默认情况下是不能将字段更新为null的,如果要更新字段为null,需要进行以下处理,这篇文章主要给大家介绍了关于Mybatis-plus更新字段为null的两种常用方法及优化,需要的朋友可以参考下
    2024-03-03
  • JPA使用乐观锁应对高并发方式

    JPA使用乐观锁应对高并发方式

    这篇文章主要介绍了JPA使用乐观锁应对高并发方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • SpringBoot报错Invalid bound statement (not found)问题排查和解决方案

    SpringBoot报错Invalid bound statement (not found)问题排查和解决方案

    这篇文章主要介绍了SpringBoot报错Invalid bound statement (not found)问题排查和解决方案,文中通过图文结合的方式讲解的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
    2024-03-03
  • 浅谈springboot之JoinPoint的getSignature方法

    浅谈springboot之JoinPoint的getSignature方法

    这篇文章主要介绍了springboot之JoinPoint的getSignature方法,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-06-06
  • SpringBoot Admin用法实例讲解

    SpringBoot Admin用法实例讲解

    在本篇文章里小编给大家整理的是一篇关于SpringBoot Admin用法实例内容,有需要的朋友们可以参考学习下。
    2019-10-10
  • springboot使用JdbcTemplate完成对数据库的增删改查功能

    springboot使用JdbcTemplate完成对数据库的增删改查功能

    这篇文章主要介绍了springboot使用JdbcTemplate完成对数据库的增删改查功能,需要的朋友可以参考下
    2017-12-12
  • Spring Boot 整合 Thymeleaf 实例分享

    Spring Boot 整合 Thymeleaf 实例分享

    这篇文章主要分享了Spring Boot整合Thymeleaf,Thymeleaf是新一代的Java模板引擎,类似于Velocity、FreeMarker等传统引擎,关于其更多相关内容,需要的小伙伴可以参考一下
    2022-05-05
  • Java详解entity转换到vo过程

    Java详解entity转换到vo过程

    这篇文章将用实例来和大家介绍一下entity转换到vo的方法过程。文中的示例代码讲解详细,对我们学习Java有一定的帮助,需要的可以参考一下
    2022-06-06

最新评论