Java 枚举(enum)剖析

目录

Java 枚举(enum)概述

枚举常量 & values 遍历

枚举属性、方法、参数

枚举实现接口

枚举定义抽象方法、静态方法

同一工具类中维护多个枚举

switch case 枚举

枚举创建单例


Java 枚举(enum)概述

1、Java JDK 1.5 新增的 enum 关键词,可以定义枚举类,如 public enum WeekEnum { }.

2、使用 enum 定义后的枚举类在编译后默认继承 java.lang.Enum 类,而不是普通的继承 Object 类。由于 Java 不支持多继承,所以枚举不能再显示的继承其他类,但是可以实现接口。

3、Enum 类默认实现了 Java.lang.Comparable 接口与 Serializable 接口。

4、enum 声明后,该类会被编译器加上 final 声明(如同 String),故枚举无法被继承。

5、枚举类内部定义的枚举值就是该类的实例,且必须在第一行定义,当类初始化时,这些枚举值会被实例化,互相以逗号分隔。 如 "Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday"。

6、枚举规定好了指定的取值范围,所有的内容只能从指定的范围中取得。

7、枚举是一种类型,用于定义变量,以限制变量的赋值;通过 "枚举名.值" 取得枚举值,每个值都是一个 Enum 实例。

8、枚举是一个特殊的类,可以定义自己的 field(包括静态属性)、方法(包括静态方法)、可以实现接口,也可以定义自己的构造器。

9、枚举类的构造方法默认用 private 修饰的,且不能出现 public 构造方法,因此无法 new 一个枚举对象。

10、实际编程中往往存在着这样的 "数据集",它们的数值是稳定的、元素个数是有限的,例如星期一到星期日,春夏秋冬四季等等,很多时候大家选择使用常量。 JDK 1.5 开始有了枚举,其实可以把相关的常量放到一个枚举类型里,枚举提供了比常量更多的方法,使用起来更加方便。

枚举的构造器私有,每一个枚举值都是一个枚举实例,编译后自动产生。

枚举值的参数与构造器的参数相对应:

  枚举值后面没跟参数时,对应构造器的无参构造,
  枚举值后面有跟参数时,必须要有参数个数且类型相同的构造器与之对应,以及设置相应的成员变量。

枚举编译构建实例顺序:枚举值后面的实参值->找到对应的构造方法->注入给相应的成员变量。因为构造器可以重载,所以枚举值后面的参数可以不同,包括类型与个数。
每个枚举值既可以调用自己独有的属性,即后面的参数值,也可以调用公共的属性,即可调用自己下面独有的方法,也可调用公共的方法。
当枚举值/枚举常量没有带参数时,则没必要构造器,反之如果枚举值有参数,则必须有构造器与之对应。
枚举常用API方法
方法描述
toStringEnum 类重写了 toString 方法,返回枚举常量名。
values 每个枚举类都有一个 values 方法,该方法可以遍历枚举类的所有实例.
static Enum valueOf(Class enumClass, String name)返回指定名字、给定类的枚举常量
boolean equals(Object other)比较枚举是否相等。也可以直接使用 == 比较是否相等。

枚举常量 & values 遍历

1、定义枚举。

public enum WeekEnum1 {
    /**
     * 最简单的枚举形式,使用逗号分隔,结尾分号此时可以省略
     * 每一个值都代表当前的枚举实例,通过 枚举名.值 获取
     */
    Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday
}
    /**
     * 每个枚举类都有一个 values 方法,该方法可以遍历枚举类的所有实例.
     * 1、可以直接通过类名调用 values 方法,小哥哥都是一样的。
     * 2、也可以通过枚举常量调用 values 方法,小哥哥都是一样的。
     */
    @Test
    public void testValues() {
        WeekEnum1[] values = WeekEnum1.values();
        for (WeekEnum1 weekEnum1 : values) {
            // Monday	Tuesday	Wednesday	Thursday	Friday	Saturday	Sunday
            System.out.print(weekEnum1 + "\t");
        }
        System.out.println();
        WeekEnum1[] values1 = WeekEnum1.Sunday.values();
        for (WeekEnum1 weekEnum1 : values1) {
            // Monday	Tuesday	Wednesday	Thursday	Friday	Saturday	Sunday
            System.out.print(weekEnum1 + "\t");
        }
    }

src/main/java/org/example/enums/WeekEnum1.java · 汪少棠/java-se - Gitee.com

测试枚举:src/main/java/org/example/enums/WeekEnumTest1.java · 汪少棠/java-se - Gitee.com

枚举属性、方法、参数

1、枚举像普通的类一样可以添加属性和方法(包括静态或非静态的属性或方法)。注意枚举值要写在最前面,且以分号结尾,否则编译出错。

2、枚举常量后面可以接括号定义枚举参数,这些参数会通过对应的构造器自动给属性赋值。"枚举参数 -> 对应的构造器 -> 属性" 完成赋值。

public enum WeekEnum2 {
    /**
     * 枚举值写在最前面,有其他内容时,必须以分号结尾。
     * 因为枚举只能通过常量获取枚举实例,所以枚举参数必须与构造器中的参数对应
     * 匹配两个参数的构造器创建 1-6 实例
     * 匹配三个参数的构造器创建 Sunday 实例
     */
    Monday(1, "星期一"),
    Tuesday(2, "星期二"),
    Wednesday(3, "星期三"),
    Thursday(4, "星期四"),
    Friday(5, "星期五"),
    Saturday(6, "星期六"),
    Sunday(7, "星期天", "周末");
    /**
     * 属性名称可以随便取,只需要构造器中的参数类型必须与上面的枚举参数类型对应
     */
    private Integer code;
    private String name;
    private String ext;
    /**
     * 支持定义静态属性
     */
    public static String summary;

    /**
     * 构造器默认是 private ,外部无法 new 枚举对象,只能通过上面的常量获取实例,必须与枚举参数对应
     *
     * @param code
     * @param name
     */
    WeekEnum2(Integer code, String name) {
        this.code = code;
        this.name = name;
    }
    WeekEnum2(Integer code, String name, String ext) {
        this.code = code;
        this.name = name;
        this.ext = ext;
    }
    /**
     * 因为枚举常量的参数都是通过内部私有的构造器赋值的,无法通过外部赋值,所以没必要提供 setter方法
     * 但是可以提供 getter 方法来获取枚举参数值
     *
     * @return
     */
    public Integer getCode() {
        return code;
    }
    public String getName() {
        return name;
    }
    public String getExt() {
        return ext;
    }
    /**
     * 获取工作日 周一到周五-----支持静态方法
     *
     * @return
     */
    public static Set<WeekEnum2> getWorkDays() {
        Set<WeekEnum2> workDays = new HashSet<>(5);
        workDays.add(WeekEnum2.Monday);
        workDays.add(WeekEnum2.Tuesday);
        workDays.add(WeekEnum2.Wednesday);
        workDays.add(WeekEnum2.Thursday);
        workDays.add(WeekEnum2.Friday);
        return workDays;
    }
    /**
     * 根据 星期数字获取对应的星期中文
     *
     * @param code 星期几 [1,7]
     * @return :返回中文,星期一、星期二、...
     */
    public static WeekEnum2 getWorkDayByCode(Integer code) {
        WeekEnum2[] values = WeekEnum2.values();
        for (WeekEnum2 value : values) {
            if (StrUtil.equals(String.valueOf(value.code), String.valueOf(code))) {
                return value;
            }
        }
        return null;
    }
}

src/main/java/org/example/enums/WeekEnum2.java · 汪少棠/java-se - Gitee.com

src/main/java/org/example/enums/WeekEnum2Test.java · 汪少棠/java-se - Gitee.com

枚举实现接口

1、先准备一个接口:

import java.util.Map;
public interface WeekEnumInterface {
    Integer getCode();
    String getName();
    Map<String, Object> getDataMap();
}

src/main/java/org/example/enums/WeekEnum3Interface.java · 汪少棠/java-se - Gitee.com

2、定义枚举并实现接口

public enum WeekEnum3 implements WeekEnum3Interface {
    //枚举值写在最前面,有其他内容时,必须以分号结尾。
    //因为枚举只能通过常量获取枚举实例,所以枚举参数必须与构造器中的参数对应
    //匹配两个参数的构造器创建实例
    Monday(1, "星期一"),
    Tuesday(2, "星期二"),
    Wednesday(3, "星期三"),
    Thursday(4, "星期四"),
    Friday(5, "星期五"),
    Saturday(6, "星期六"),
    Sunday(7, "星期天");
    /**
     * 属性名称可以随便取,但是构造器中的参数类型必须与上面的枚举参数类型对应
     */
    private Integer code;
    private String name;
    /**
     * 构造器默认是 private ,外部无法 new 枚举对象,只能通过上面的常量获取实例,必须与枚举参数对应
     *
     * @param code
     * @param name
     */
    WeekEnum3(Integer code, String name) {
        this.code = code;
        this.name = name;
    }
    @Override
    public Integer getCode() {
        return this.code;
    }
    @Override
    public String getName() {
        return this.name;
    }
    /**
     * 将整个枚举参数转为 Map 结构
     *
     * @return
     */
    @Override
    public Map<String, Object> getDataMap() {
        Map<String, Object> dataMap = new HashMap<>(WeekEnum3.values().length);
        for (WeekEnum3 weekEnum : WeekEnum3.values()) {
            dataMap.put(weekEnum.code + "", weekEnum.name);
        }
        return dataMap;
    }
}

src/main/java/org/example/enums/WeekEnum3.java · 汪少棠/java-se - Gitee.com

测试代码:

src/main/java/org/example/enums/WeekEnum3Test.java · 汪少棠/java-se - Gitee.com

枚举定义抽象方法、静态方法

1、枚举中可以有抽象方法,且由枚举值/枚举常量提供方法实现。枚举类如下:

public enum WeekEnum4 {
    /**
     * 枚举值写在最前面,有其他内容时,必须以分号结尾。
     * 因为枚举只能通过常量获取枚举实例,所以枚举参数必须与构造器中的参数对应
     */
    Monday(1, "星期一") {
        @Override
        public String toSplitString() {
            return Monday.code + "," + Monday.name;
        }
    },
    Tuesday(2, "星期二") {
        @Override
        public String toSplitString() {
            return Tuesday.getCode() + "," + Tuesday.getName();
        }
    };
    /**
     * 属性名称可以随便取,但是构造器中的参数类型必须与上面的枚举参数类型对应
     */
    private Integer code;
    private String name;
    /**
     * 全部枚举值放入到常量中
     * 在静态代码块中为其赋值
     */
    private static final Map<Integer, WeekEnum4> weekEnum4Map = new HashMap<>();
    static {
        for (WeekEnum4 weekEnum4 : values()) {
            weekEnum4Map.put(weekEnum4.getCode(), weekEnum4);
        }
    }
    /**
     * 构造器默认是 private ,外部无法 new 枚举对象,只能通过上面的常量获取实例,必须与枚举参数对应
     *
     * @param code
     * @param name
     */
    WeekEnum4(Integer code, String name) {
        this.code = code;
        this.name = name;
    }
    public Integer getCode() {
        return code;
    }
    public String getName() {
        return name;
    }
    /**
     * 方法要是 public 修饰外部才能调用
     *
     * @return
     */
    public abstract String toSplitString();
    /**
     * 根据数字获取星期枚举
     * 静态方法,方便通过类名调用。
     *
     * @param index
     * @return
     */
    public static WeekEnum4 of(Integer index) {
        return weekEnum4Map.get(index);
    }
    /**
     * 获取全部枚举项
     *
     * @return
     */
    public static List<WeekEnum4> list() {
        WeekEnum4[] values1 = WeekEnum4.values();
        ArrayList<WeekEnum4> weekEnum4s = Lists.newArrayList(values1);
        return weekEnum4s;
    }
}

测试代码:src/main/java/org/example/enums/WeekEnum4Test.java · 汪少棠/java-se - Gitee.com

同一工具类中维护多个枚举

public class EnumComm {
    /**
     * 红绿灯颜色枚举
     */
    public enum ColorEnum {
        Red("red", "红色"),
        Yellow("yellow", "黄色"),
        Green("green", "绿色");
        private String code;
        private String name;
        ColorEnum(String code, String name) {
            this.code = code;
            this.name = name;
        }
        public String getCode() {
            return code;
        }
        public String getName() {
            return name;
        }
    }
    /**
     * 系统上线省份枚举
     */
    public enum AreaEnum {
        HuNan("43", "湖南"),
        HeNan("41", "河南"),
        LiaoNiang("21", "辽宁");
        private String code;
        private String name;
        AreaEnum(String code, String name) {
            this.code = code;
            this.name = name;
        }
        public String getCode() {
            return code;
        }
        public String getName() {
            return name;
        }
    }
}

src/main/java/org/example/enums/EnumComm.java · 汪少棠/java-se - Gitee.com

src/main/java/org/example/enums/EnumCommTest.java · 汪少棠/java-se - Gitee.com

src/main/java/org/example/enums/EscalationConsts.java · 汪少棠/java-se - Gitee.com

switch case 枚举

    /**
     * 枚举作为 switch (xxx) 参数时,case 中的值必须是枚举常量的非限定名称。
     * 不能是 枚举.常量 的方式,否则编译不通过:
     * An enum switch case label must be the unqualified name of an enumeration constant.
     */
    @Test
    public void testSwitchCase() {
        WeekEnum2 workDayByCode = WeekEnum2.getWorkDayByCode(9);
        switch (workDayByCode) {
            // 这种方式是编译不通过的,必须是非限定名称
            // case WeekEnum2.Monday:
            case Monday:
                System.out.println(workDayByCode.getCode());
                break;
            case Saturday:
                System.out.println(workDayByCode.getName());
                break;
            case Sunday:
                System.out.println(workDayByCode.getExt());
                break;
            default:
                System.out.println(workDayByCode);
                break;
        }
    }

src/main/java/org/example/enums/WeekEnum2Test.java · 汪少棠/java-se - Gitee.com

枚举创建单例

/**
 * 枚举创建单例
 *
 * @author wangMaoXiong
 * @version 1.0
 * @date 2022/12/16 14:30
 */
public class Person {
    private String agencyCode;
    private String idenNo;
    private String idenType;
    private String perName;
    private String sexCode;
    private String control;
    /**
     * 私有化构造函数
     */
    private Person() {
    }
    private enum SingletonEnum {
        /**
         * 枚举类内部定义的枚举值就是该类的实例,必须在第一行定义,当类初始化时,这些枚举值会被实例化.
         * 创建一个枚举对象,该对象天生为单例。
         * 枚举INSTANCE会在类加载初始化的时候创建,而Java类的加载和初始化过程都是线程安全的。
         */
        INSTANCE;
        /**
         * 枚举是一个特殊的类,可以定义自己的 field(包括静态属性)、方法(包括静态方法)、可以实现接口,也可以定义自己的构造器。
         */
        private Person person;

        /**
         * 枚举类的构造方法默认用 private 修饰的,且不能出现 public 构造方法,因此无法 new 一个枚举对象。
         */
        SingletonEnum() {
            person = new Person();
        }

        public Person getInstance() {
            return person;
        }
    }
    /**
     * 对外暴露一个获取单例对象的静态方法
     *
     * @return
     */
    public static Person getInstance() {
        return SingletonEnum.INSTANCE.getInstance();
    }
   
    // 省略 getter、setter、toString 方法
}

src/main/java/org/example/enums/Person.java · 汪少棠/java-se - Gitee.com

src/main/java/org/example/enums/PersonTest.java · 汪少棠/java-se - Gitee.com

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

蚩尤后裔-汪茂雄

芝兰生于深林,不以无人而不芳。

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

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

打赏作者

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

抵扣说明:

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

余额充值