zoukankan      html  css  js  c++  java
  • 浅谈 Java 中的枚举

    枚举也就是一一列举,常用来表示那些可以明确范围的集合,比方说性别,季节,星期,月份等。

    在 JDK 1.5 才出现枚举类,在没有出现枚举类之前,我们要表示几个确定的值通常会使用常量来表示,形如

        public static final Integer SPRING = 1;
        public static final Integer SUMMER = 2;
        public static final Integer FALL = 3;
        public static final Integer WINTER = 4;

    我们可以使用枚举类来表示,这也就是最简单的枚举。

    enum Season{
        SPRING,SUMMER,FALL,WINTER;
    }

    那么枚举类和定义常量相比有什么优势呢?

    安全,我们看上面的代码可以知道,使用常量表示的季节都是 Integer 类型的,而这个类型的数据范围太大了,而使用枚举就限制了数据的域。枚举可以理解为几个常量的集合,数据不太会改变,使用枚举之后语义更加明确,因为数据域不大。

    关于枚举类,有几点需要注意:

    1. enum 和 class ,interface 的地位一样

    2. 使用 enum 定义的枚举类默认继承了 java.lang.Enum,而不是继承 Object 类。枚举类可以实现一个或多个接口,不能再继承其他类了。

    3. 枚举类的所有实例都必须放在第一行展示,不需使用 new 关键字,不需显式调用构造器。自动添加 public static final 修饰。

    4. 枚举类的构造器只能是私有的。

    关于第 4 点,我要说枚举类的定义是单例模式的,单例模式要求构造器私有化,不允许在外部创建新的对象,你想呀,枚举类的作用就是准确的表示出同一类别下的不同数据。在我们定义的时候已经创建好了,所以跟本不需要也不能在外部继续创建新的对象。故,需要将构造器私有化。

    枚举类说的通俗点就是被阉割的类,我们使用类可以创建对象,而枚举类在定义的时候就会指定创建的对象有哪些。你没有显示的写代码创建,不过是由于 JVM 自动给你加上去了。待会看看枚举类被反编译之后的情况就会理解。

    枚举类中可以定义属性和方法。

    enum Season{
    
        SPRING("春天","一年之计在于春"),SUMMER("夏天","夏天好热 ~ "),
        FALL("秋天","秋水共长天一色"),WINTER("冬天","冬天好冷 ~ ");
    
        // 添加枚举对象的名称
        private final String name;
    
        // 添加枚举对象的描述
        private final String desc;
    
        private Season(String name,String desc){
            this.name = name;
            this.desc = desc;
        }
    
        public String getName(){
            return name;
        }
    
        public String getDesc(){
            return desc;
        }
    }

    我们可以看到,有一个带参的私有构造函数,所以在定义枚举的时候可以直接赋值,而调用创建对象是由虚拟机自动完成的,还可以添加更多的属性,我们可以正常使用枚举对象。

    // 获取所有的枚举对象,返回的是数组
    Season[] values = Season.values();
    for (Season season : values) {
    System.out.println(season.getName() + " : " + season.getDesc());
    }
    
    春天 : 一年之计在于春
    夏天 : 夏天好热 ~ 
    秋天 : 秋水共长天一色
    冬天 : 冬天好冷 ~

    枚举类中实现抽象方法

    这肯定有点迷糊,我们知道含有抽象方法的类是抽象类,那为什么枚举类不是 abstract 的也可以含有抽象方法呢 ?我们先来看看实现,待会说原因。

    enum Season{
    
        SPRING("春天","一年之计在于春") {
            @Override
            public Season getNextSeason() {
                return Season.valueOf("SUMMER");
            }
        },SUMMER("夏天","夏天好热 ~ ") {
            @Override
            public Season getNextSeason() {
                return Season.valueOf("FALL");
            }
        },
            ... 省略
            ... 省略
            ... 省略
    
        // 定义了一个抽象方法,获取下一个季节
        public abstract Season getNextSeason();
    }
    
    

    测试代码如下

    public static void main(String[] args) {
        String name = Season.SPRING.getNextSeason().getName();
        System.out.println(name); // 夏天
    }

    是不是有种似懂非懂的感觉,没关系,我们来反编译看一看枚举类的内部构造你就会明白。

    举个简单的例子来看一看枚举类的原理。就拿一个最简单的枚举来说明情况。

    public enum SeasonEnum {
        SPRING,SUMMER,FALL,WINTER;
    }

    看一看反编译之后的代码,我使用的反编译工具是 jad 。

    public final class SeasonEnum extends Enum
    {
    
        public static SeasonEnum[] values()
        {
            return (SeasonEnum[])$VALUES.clone();
        }
    
        public static SeasonEnum valueOf(String s)
        {
            return (SeasonEnum)Enum.valueOf(SeasonEnum, s);
        }
    
        private SeasonEnum(String s, int i)
        {
            super(s, i);
        }
    
        public static final SeasonEnum SPRING;
        public static final SeasonEnum SUMMER;
        public static final SeasonEnum FALL;
        public static final SeasonEnum WINTER;
        private static final SeasonEnum $VALUES[];
    
        static 
        {
            SPRING = new SeasonEnum("SPRING", 0);
            SUMMER = new SeasonEnum("SUMMER", 1);
            FALL = new SeasonEnum("FALL", 2);
            WINTER = new SeasonEnum("WINTER", 3);
            $VALUES = (new SeasonEnum[] {
                SPRING, SUMMER, FALL, WINTER
            });
        }
    }

    可以看到枚举类本质上就是一个继承了 Enum 的一个单例最终类,而我们定义的枚举对象也是在静态代码块中初始化了,同时我们也可以看到 values 方法的实现就是返回实例对象的数组,也就是枚举对象的数组,valueOf 方法接收一个字符串,返回的是字符串对应的枚举对象,若是找不到,会报错。

    看到这我们也就能理解为什么我们可以在枚举类中定义抽象方法了,我们使用内部类实现了抽象方法,对应的每个对象在创建时都会实现相应的抽象方法。同样的道理,枚举类也可以实现接口,这里就不演示了。

    说了这么多,也知道了枚举的好处,但是不得不说的是我在实际的项目中,枚举类的使用还真不多,下面就看看枚举类可以有哪些用处,以后有这种需求就可以考虑使用枚举来实现。

    switch 语句支持枚举类型是从 JDK 1.5 才开始的,因为此时才有枚举这个特性。我们看一看具体的使用。

    /**
     * 服务器响应码
     */
    public enum ResponseCode {
    
        SUCCESS(200,"访问成功"),FAIL(404,"页面不存在"),ERROR(500,"服务器内部错误");
    
        private Integer num;
        private String desc;
    
        private ResponseCode(Integer num,String desc){
            this.num = num;
            this.desc = desc;
        }
    
        public Integer getNum() {
            return num;
        }
    
        public String getDesc() {
            return desc;
        }
    
        /*
         * 通过返回码得到枚举对象
         */
        public static ResponseCode getByNum(Integer num){
            for(ResponseCode code : values()){
                if(code.getNum().equals(num)){
                    return code;
                }
            }
            return null;
        }
    }
    =============测试=====================
        public static void main(String[] args) {
            ResponseCode code = ResponseCode.getByNum(200);
            switch (code) {
            case SUCCESS:
                System.out.println("成功");
                break;
    
            default:
                break;
            }
        }

    在我做过的项目中,只有一处用到过枚举,用来记录字典的值,比方说,我写一个工具类,记录项目中使用到的所有字典相关数据。形如这样

    public class Keys {
        enum Sex{
            MALE,FEMALE;
        }
        enum State{
            SUCCESS,FAIL;
        }
        enum Month{ 
        }
        enum Week{      
        }
    
        public static void main(String[] args) {
            Keys.Sex.MALE.name();
        }
    }

    但是在后面发现,还有更好用的配置字典的方式,创建一个字典类,将所有的字典数据放在一张表中,我们使用字典类来操作,这样要比上面使用枚举要好。

  • 相关阅读:
    Serialize and Deserialize Binary Tree
    sliding window substring problem汇总贴
    10. Regular Expression Matching
    《深入理解计算机系统》(CSAPP)读书笔记 —— 第七章 链接
    程序员如何写一份合格的简历?(附简历模版)
    9个提高代码运行效率的小技巧你知道几个?
    《深入理解计算机系统》(CSAPP)读书笔记 —— 第六章 存储器层次结构
    24张图7000字详解计算机中的高速缓存
    《深入理解计算机系统》(CSAPP)实验四 —— Attack Lab
    《深入理解计算机系统》(CSAPP)读书笔记 —— 第五章 优化程序性能
  • 原文地址:https://www.cnblogs.com/YJK923/p/9597022.html
Copyright © 2011-2022 走看看