zoukankan      html  css  js  c++  java
  • Java基础

    引言

    如果说泛型是对类型的限制,那么枚举则是对数据范围的限制了

    语法

    基础语法

    public enum WeekDay {
        MON(1,"MONDAY");
    
        private int code;
        private String desc;
        WeekDay(int code,String desc){
            this.code = code;
            this.desc = desc;
        }
    }
    

    可以看到,枚举类相较于普通的类,在成员变量和成员方法上几乎没有区别
    只是在定义完了成员变量和方法之后,可以在类定义的最前面提前定义好一些枚举对象
    其实这只是一个语法糖,枚举对象其实就类似下面这样(详细内容在实现原理小节中有叙述)

        // public static final WeekDay MON = new WeekDay(1,"MONDAY");
        MON(1,"MONDAY");
    

    定义方法

    因为枚举其实就是个普通的类,所以我们可以为它添加方法

    public enum WeekDay {
        // public static final WeekDay MONDAY = new WeekDay(1,"周一");
        MON(1,"MONDAY");
    
        private int code;
        private String desc;
        WeekDay(int code,String desc){
            this.code = code;
            this.desc = desc;
        }
        // 添加方法
        public int getCode() {
            return this.code;
        }
    }
    

    常用方法

    枚举原生会有一些常用的方法,这里列举一下

    name()

    枚举方法的名称

    WeekDay.MON.name();  // MON
    

    ordinal()

    枚举定义的序号,即枚举定义的顺序,从前到后依次递增

    WeekDay.MON.ordinal(); // 0
    

    valueOf

    根据值返回枚举对象,默认是根据name返回枚举对象

    WeekDay.valueOf("MON").getDesc();  // MONDAY
    

    如果你想根据其他的值获取枚举对象的话,可以自己再写一个工具类

    values

    Enum没有values方法
    枚举对象可以调用values方法,但是父类Enum中却没有这个方法,因为这个方法是编译器在编译时给枚举类加上的
    所以当你把枚举向上转型为Enum时,你无法使用values方法

    WeekDay.values(); 
    
    // 为了方便打印,你可以转成list,另外这里我加了一个周二
    Arrays.asList(WeekDay.values());  // [MON,TUE] 
    

    注意:values返回的是原数组的拷贝

    getEnumConstants

    在上面个的values方法中,我们虽然无法针对父类Enum使用values方法,但是可以使用getEnumConstants方法,因为这个方法属于Class

    WeekDay[] weekDays = WeekDay.class.getEnumConstants();
    // 同样的,你可以转成List
    Arrays.asList(weekDays);  // [MON,TUE]
    

    实现原理

    基本原理

    枚举其实也只是普通的类,但是要搞清楚它是如何完成数据范围限制的

    1. 枚举就是一个常量类(final的),并且构造方法是私有的,所以你没办法新增更多对象
    2. 枚举对象也是静态final的对象,静态保证对象唯一,final保证对象不会被替换

    反编译结果

    public final class WeekDay extends Enum<WeekDay> {
        public static final /* enum */ WeekDay MON = new WeekDay("MON", 0, 1, "MONDAY");
        private int code;
        private String desc;
        private static final /* synthetic */ WeekDay[] $VALUES;
    
        public static WeekDay[] values() {
            return (WeekDay[])$VALUES.clone();
        }
    
        public static WeekDay valueOf(String name) {
            return Enum.valueOf(WeekDay.class, name);
        }
    
        private WeekDay(String string, int n, int code, String desc) {
            super(string, n);
            this.code = code;
            this.desc = desc;
        }
    
        static {
            $VALUES = new WeekDay[]{MON};
        }
    }
    

    枚举 + 抽象方法

    理解原理后,再来看一种枚举的用法,例如现在我们有这样一个需求:
    针对不同的工作类型,计算工资(时薪):

    1. 上班 :工资 * 1
    2. 加班:工资 * 2
    3. 请假:工资 * 0

    我们可以像下面这样做:

    public enum SalaryCouter {
        WORK_SALARY(1) {
            @Override
            public int countSalary(int baseSalary) {
                return baseSalary * 1;
            }
        },
        OVERTIME_SALARY(2) {
            @Override
            public int countSalary(int baseSalary) {
                return baseSalary * 2;
            }
        },
        LEAVE_SALARY(3) {
            @Override
            public int countSalary(int baseSalary) {
                return 0;
            }
        };
        
        private int code;
        SalaryCouter(int code) {
            this.code = code;
        }
    
        public abstract int countSalary(int baseSalary);
    
    }
    

    测试一下

            int totalSalary = 8 * SalaryCouter.WORK_SALARY.countSalary(50);
    

    理解原理之后,相信理解这个例子也不困难了,这就相当于是在创建枚举对象时使用了匿名对象的方式

    配合客户端

    当然了,你这里会吐槽,你这里写死了是哪种工资结算方式,那么前端传过来的时候怎么知道呢?
    其实,这里只需要简单的改动下即可

    1. 在枚举类中添加类似valueOf的工具方法
    2. 前端根据工具方法传值即可(例如这里根据code)
    • 添加工具方法
      这里只是简单写了下,你也可以使用map存储code和对应的枚举实例进行缓存
    public static SalaryCouter getSalaryCounter(int code) {
            switch (code) {
                case 1:
                    return WORK_SALARY;
                case 2:
                    return OVERTIME_SALARY;
                case 3:
                    return LEAVE_SALARY;
                default:
                    return WORK_SALARY;
            }
        }
    
    • 测试一下
    // 这里的1就是前端对应传过来的值
    int totalSalary2 = SalaryCouter.getSalaryCounter(1)
                                            .countSalary(50);
    

    小结

    这样写的好处是,未来不论增加多少种工资结算的方式,客户端的代码都不需要变动

    枚举 vs 常量类

    枚举的优点:

    1. 因为是通过对象保存的,所以说可以存储更多信息,特别是需要绑定到一起的信息,例如状态码和状态信息
    2. 枚举 + 抽象方法:可以针对某一个功能(例如计算工资的方式)提供有限的实现方式(枚举无法被继承,你也无法新建一个枚举对象)
  • 相关阅读:
    7A
    map最最最基本用法
    cccc超级酱油心得
    scu-4445
    初学算法之广搜
    初学算法之最基础的stl队列
    初学算法之筛选素数法
    go 虎牙爬取
    php使用xpath爬取内容
    go xpath
  • 原文地址:https://www.cnblogs.com/bax-life/p/14683099.html
Copyright © 2011-2022 走看看