【小家Java】深入理解Java枚举类型(enum)及7种常见的用法(含EnumMap和EnumSet)(上)

简介: 【小家Java】深入理解Java枚举类型(enum)及7种常见的用法(含EnumMap和EnumSet)(上)

前文


这次当我入职一家新公司的时候,编写代码发现,里面还在大量的使用public static final…这种语句来神马一些状态常量。


很多时候,虽然都能暂时完成一样的功能,但武功高低,一看便知。因此我加入之后,迅速全面引入枚举类型,并且指定枚举的使用规范、统一实现的接口。。。


什么是枚举类型


枚举类型是Java 5中新增特性的一部分,它是一种特殊的数据类型,之所以特殊是因为它既是一种类(class)类型却又比类类型多了些特殊的约束,但是这些约束的存在也造就了枚举类型的简洁性、安全性以及便捷性。


枚举类型的定义


这段代码,是在enum没引入之前:


public class DayDemo {
    public static final int MONDAY =1;
    public static final int TUESDAY=2;
    public static final int WEDNESDAY=3;
    public static final int THURSDAY=4;
    public static final int FRIDAY=5;
    public static final int SATURDAY=6;
    public static final int SUNDAY=7;
}


上述的常量定义常量的方式称为int枚举模式,这样的定义方式并没有什么错,但它存在许多不足:


  1.如在类型安全和使用方便性上并没有多少好处


  2.如果存在定义int值相同的变量,混淆的几率还是很大的,编译器也不会提出任何警告


  3.操作上,比如我要拿到所有的枚举值,或者根据枚举值拿到具体的名字等都非常的不方便因此这种方式在枚举出现后并不提倡,现在我们利用枚举类型来重新定义上述的常量,同时也感受一把枚举定义的方式,如下定义周一到周日的常量


//枚举类型,使用关键字enum
public enum Day {
    MONDAY, TUESDAY, WEDNESDAY,
    THURSDAY, FRIDAY, SATURDAY, SUNDAY
}


相当简洁,使用起来也是异常的方便(下面会着重讲解它的用法)。


枚举的真身


需要看真身,首先我们得看看编译后的.class文件。


/**
 * @author fangshixiang@vipkid.com.cn
 * @description
 * @date 2018-11-03 16:49
 */
public enum DayEnum {
    MONDAY, TUESDAY, WEDNESDAY,
    THURSDAY, FRIDAY, SATURDAY, SUNDAY
}


查看.class文件如下:



我们发现它和普通的class文件一样,还是会生成一个同名的.class文件。现在我们反编译看看.class文件的内容:


public final class DayEnum extends Enum<DayEnum> {
    //编译器为我们添加的静态的values()方法
    public static DayEnum[] values() {
        return (DayEnum[])$VALUES.clone();
    }
    //编译器为我们添加的静态的valueOf()方法,注意间接调用了Enum也类的valueOf方法
    public static DayEnum valueOf(String s) {
        return (DayEnum)Enum.valueOf(com/fsx/run/enums/DayEnum, s);
    }
    //私有构造函数 只能由编译器来调用
    private DayEnum(String enumName, int index) {
        super(enumName, index);
    }
    //前面定义的7种枚举实例
    public static final DayEnum MONDAY;
    public static final DayEnum TUESDAY;
    public static final DayEnum WEDNESDAY;
    public static final DayEnum THURSDAY;
    public static final DayEnum FRIDAY;
    public static final DayEnum SATURDAY;
    public static final DayEnum SUNDAY;
    //装载所有实例的一个数组
    private static final DayEnum $VALUES[];
    //通过静态代码快实例这些多例
    static {
        MONDAY = new DayEnum("MONDAY", 0);
        TUESDAY = new DayEnum("TUESDAY", 1);
        WEDNESDAY = new DayEnum("WEDNESDAY", 2);
        THURSDAY = new DayEnum("THURSDAY", 3);
        FRIDAY = new DayEnum("FRIDAY", 4);
        SATURDAY = new DayEnum("SATURDAY", 5);
        SUNDAY = new DayEnum("SUNDAY", 6);
        //都装载进去
        $VALUES = (new DayEnum[] {
                MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
        });
    }
}


看到了enum类型编译后的真身,很多结果都一目了然了有木有。


我们注意到,DayEnum类是final类型的,将无法被继承。而且该类继承自java.lang.Enum类(它是一个抽象类,所有的enum类型的类都是它的子类,提供很多方法和定义)


这里提醒大家一点,Enum类内部会有一个构造函数,该构造函数只能有编译器调用,我们是无法手动操作的


枚举的Class对象


需求:我们需要一次性获取到所有的枚举值对象:


    public static void main(String[] args) {
        DayEnum[] values = DayEnum.values();
        DayEnum[] enumConstants = DayEnum.class.getEnumConstants();
        //判断某个class是否为枚举类型
        System.out.println(MONDAY.getClass().isEnum()); //true
    }


enum中定义抽象方法


与常规抽象类一样,enum类允许我们为其定义抽象方法,然后使每个枚举实例都实现该方法,以便产生不同的行为方式,注意abstract关键字对于枚举类来说并不是必须的如下:


public enum EnumDemo3 {
    FIRST{
        @Override
        public String getInfo() {
            return "FIRST TIME";
        }
    },
    SECOND{
        @Override
        public String getInfo() {
            return "SECOND TIME";
        }
    }
    ;
    /**
     * 定义抽象方法
     * @return
     */
    public abstract String getInfo();
    //测试
    public static void main(String[] args){
        System.out.println("F:"+EnumDemo3.FIRST.getInfo());
        System.out.println("S:"+EnumDemo3.SECOND.getInfo());
        /**
         输出结果:
         F:FIRST TIME
         S:SECOND TIME
         */
    }
}



相关文章
|
2天前
|
安全 Java 测试技术
🎉Java零基础:全面解析枚举的强大功能
【10月更文挑战第19天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
92 60
|
6天前
|
存储 安全 Java
深入理解Java中的FutureTask:用法和原理
【10月更文挑战第28天】`FutureTask` 是 Java 中 `java.util.concurrent` 包下的一个类,实现了 `RunnableFuture` 接口,支持异步计算和结果获取。它可以作为 `Runnable` 被线程执行,同时通过 `Future` 接口获取计算结果。`FutureTask` 可以基于 `Callable` 或 `Runnable` 创建,常用于多线程环境中执行耗时任务,避免阻塞主线程。任务结果可通过 `get` 方法获取,支持阻塞和非阻塞方式。内部使用 AQS 实现同步机制,确保线程安全。
|
2月前
|
安全 Java 索引
Java——反射&枚举
本文介绍了Java反射机制及其应用,包括获取Class对象、构造方法、成员变量和成员方法。反射允许在运行时动态操作类和对象,例如创建对象、调用方法和访问字段。文章详细解释了不同方法的使用方式及其注意事项,并展示了如何通过反射获取类的各种信息。此外,还介绍了枚举类型的特点和使用方法,包括枚举的构造方法及其在反射中的特殊处理。
58 9
Java——反射&枚举
|
2月前
|
Java
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
75 5
|
2月前
|
安全 Java 开发者
Java 枚举(enum)详解
Java 中的枚举(`enum`)是一种特殊的数据类型,用于定义一组固定的常量,提升代码的类型安全性和可读性。枚举使用 `enum` 关键字定义,支持方法和构造函数,具有类型安全、单例、自动序列化等特点,并且可以遍历和用于 `switch` 语句中。实际应用包括状态机、指令集、类型标识等场景。枚举使代码更加清晰易维护。
|
2月前
|
Java
Java 正则表达式高级用法
Java 中的正则表达式是强大的文本处理工具,用于搜索、匹配、替换和分割字符串。`java.util.regex` 包提供了 `Pattern` 和 `Matcher` 类来高效处理正则表达式。本文介绍了高级用法,包括使用 `Pattern` 和 `Matcher` 进行匹配、断言(如正向和负向前瞻/后顾)、捕获组与命名组、替换操作、分割字符串、修饰符(如忽略大小写和多行模式)及 Unicode 支持。通过这些功能,可以高效地处理复杂文本数据。
|
2月前
|
存储 Java 数据处理
Java 数组的高级用法
在 Java 中,数组不仅可以存储同类型的数据,还支持多种高级用法,如多维数组(常用于矩阵)、动态创建数组、克隆数组、使用 `java.util.Arrays` 进行排序和搜索、与集合相互转换、增强 for 循环遍历、匿名数组传递以及利用 `Arrays.equals()` 比较数组内容。这些技巧能提升代码的灵活性和可读性,适用于更复杂的数据处理场景。
|
2月前
|
安全 Java
Java switch case隐藏用法
在 Java 中,`switch` 语句是一种多分支选择结构,常用于根据变量值执行不同代码块。除基本用法外,它还有多种进阶技巧,如使用字符串(Java 7 开始支持)、多个 `case` 共享代码块、不使用 `break` 实现 “fall-through”、使用枚举类型、使用表达式(Java 12 及以上)、组合条件以及使用标签等。这些技巧使代码更加简洁、清晰且高效。
|
3月前
|
Java 数据处理
Java IO 接口(Input)究竟隐藏着怎样的神秘用法?快来一探究竟,解锁高效编程新境界!
【8月更文挑战第22天】Java的输入输出(IO)操作至关重要,它支持从多种来源读取数据,如文件、网络等。常用输入流包括`FileInputStream`,适用于按字节读取文件;结合`BufferedInputStream`可提升读取效率。此外,通过`Socket`和相关输入流,还能实现网络数据读取。合理选用这些流能有效支持程序的数据处理需求。
39 2
|
3月前
|
Java
Java枚举使用的基本案例
这篇文章是关于Java枚举的基本使用,通过一个指令下发的代码案例,展示了如何定义枚举、使用枚举以及如何通过枚举实现指令的匹配和处理。