【Java】深入剖析Java枚举类

news2024/11/18 17:32:24

在这里插入图片描述

目录

  • 定义
    • 1)定义
    • 2)内部实现
    • 3)方法与源码
  • 高级特性
    • 1)switch用法
    • 2)自定义传值与构造函数
    • 3)枚举实现抽象方法
    • 4)枚举注解属性
    • 5)枚举实现接口
  • 总结

定义

1)定义

枚举类是Java 5引入的,在Java 5之前,Java并没有内置的枚举类型,只能通过自定义类来实现类似枚举的功能。例如:

public class EnumClass {  
  
    public static final int CONSTANT1 = xxx;  
  
    public static final int CONSTANT2 = xxx;  
  
    public static final int CONSTANT3 = xxx;  
  
    ...  
}  

Java 枚举类是一种特殊类型的数据结构,一般用来存储定义一些字符串,数字等数据结构。枚举类中的每个常量都称为枚举常量。枚举类在Java中使用关键字enum定义。一般枚举类格式如下:

public enum EnumClass {  
    CONSTANT1,  
    CONSTANT2,  
    CONSTANT3,  
    ...
}  

其中,EnumClass为枚举类的名称,CONSTANT1、CONSTANT2、CONSTANT3等为枚举常量的名称。枚举类的引入,提供了一种更简洁、更安全的定义枚举类型的方式。

枚举类可以直接在其他类中引用,例如:

public enum Color {  
    RED,  
    GREEN,  
    BLUE  
}  
public class ColorUtil {  
      
    private ColorUtil() {  
    }  
  
    public static void main(String[] args) {  
        Color red = Color.RED;  
    }  
}  

枚举类是类,所以当然也可以在其他类内部定义:

public class Example {  
    public enum Color {  
        RED,  
        GREEN,  
        BLUE  
    }  
  
    public static void main(String[] args) {  
        System.out.println(Color.RED);  
    }  
}  

枚举类在内部定义时,可以将其作为内部类来定义,也可以将其作为静态内部类来定义,内部定义的枚举类可以访问外部类的成员变量和方法,比如:

public class Example {  
    private static int privateVariable = 10;  
  
    public enum Color {  
        RED, GREEN, BLUE;  
  
        public void print() {  
            System.out.println(name() + " has a value of " + Example.privateVariable);  
        }  
    }  
  
    public static void main(String[] args) {  
        Example.Color.RED.print();  
    }  
}  

这段代码运行main方法的结果为:

在这里插入图片描述

2)内部实现

我们借助IDEA中的一个反编译分析插件Jadx Class Decompiler反编译刚刚创建的Color枚举类,首先安装插件如下:

在这里插入图片描述

安装完成后,右键点击需要反编译的java文件,这里选择Color.java:

在这里插入图片描述

选择01 分析字节码,可以得到分析结果如下:

在这里插入图片描述

可以看到,枚举类是public和final修饰的,这表示它不能像普通的类一样被继承,也可以看到枚举类继承自java.lang.Enum类型,并且定义了public static final修饰的三个实例变量RED GREEN BLUE,这三个实例变量实际都是Color的实例对象。
此外其内部还定义了静态的values方法,它会返回一个包含所有枚举实例的Color[]结构的列表,以及valuesOf(String input)方法,它通过传入对应的枚举常量字符串,返回对应的Color实例。

3)方法与源码

我们翻阅官方文档可以得知java.lang.Enum包含了如下一些方法(查看Enum类源码也能看到):

在这里插入图片描述

其中特有方法应属valuesOf()和ordinal(),valuesOf()刚刚已经说明,它会返回指定名称的枚举常量,例如:

public enum Color {  
    RED,   
    GREEN,   
    BLUE;  
}  
  
Color color = Color.valueOf("GREEN");  

ordinal()方法主要是获取枚举量在枚举类中的顺序,比如在上面例子中RED排在第一位,ordinal()返回值为0,示例如下:

public static void main(String[] args) {  
    Color red = Color.RED;  
    int ordinal = red.ordinal();  // ordinal = 0  
}  

另外在字节码分析结果中可以看到其实Enum是有构造方法的,但是这个构造方法用户无法调用,只有编译器可以调用,我们翻阅java.lang.Enum源码可以看到:

在这里插入图片描述

另外Enum还针对枚举常量实现了compareTo方法,并且这个compareTo方法默认是根据枚举的ordinal来对比的,也就是根据枚举在枚举类的声明顺序来对比的。

在这里插入图片描述

高级特性

1)switch用法

我们知道一般在使用switch进行判断时,可以使用整数、字符串,甚至表达式作为条件,但其实switch也支持枚举,并且不需要使用枚举的引用,代码示例如下:

import java.util.Arrays;  
import java.util.List;  
import java.util.stream.Collectors;  
  
public class ColorUtil {  
      
    private ColorUtil() {  
    }  
      
    private static String getDescription(Color color) {  
        switch(color) {  
            case RED:  
                return "The color of blood";  
            case GREEN:  
                return "The color of grass";  
            case BLUE:  
                return "The color of the sky";  
            default:  
                return "";  
        }  
    }  
      
    public static void main(String[] args) {  
        Color red = Color.RED;  
        String description = getDescription(red);  
        System.out.println(description);  
    }  
}  

运行可以得到结果如下:

在这里插入图片描述

2)自定义传值与构造函数

这个特性我本人经常使用到,首先枚举类中可以定义好属性,然后自定义构造函数,在声明枚举类实例的时候传入对应的属性值,比如在业务中可能用到的isDelete字段,我们可以定义枚举类如下:

import lombok.Getter;  
  
public enum IsDeleteEnum {  
    TRUE(1, "是"),  
    FALSE(0, "否"),  
    ;  
  
    //值描述  
    @Getter  
    private String desc;  
    //枚举值  
    @Getter  
    private Integer code;  
  
    IsDeleteEnum(Integer code, String desc) {  
        this.code = code;  
        this.desc = desc;  
    }  
}  

这里包含了两个成员变量code和desc,分别代表枚举的值和描述信息。
这个类使用了Lombok库中的@Getter注解,枚举值和名称可以被Getter方法直接访问。

如果上面这个还是初级版本,那么下面这个高级版本则更为典型和常用,我们定义了ColorEnum的枚举类,它包含RED、BLUE、GREEN三个枚举值。每个枚举值都有一个值和名称,并且有一个静态的Map用于根据值获取枚举常量。这个类还提供了一个公共的静态方法of(),用于根据给定的值返回对应的枚举常量,如果没有找到则返回null。

import lombok.Getter;  
  
import java.util.HashMap;  
import java.util.Map;  
  
public enum ColorEnum {  
    RED(0, "红色"),  
    BLUE(1, "蓝色"),  
    GREEN(2, "绿色"),  
    ;  
  
    // 枚举值  
    @Getter  
    private Integer value;  
  
    @Getter  
    private String name;  
  
    private static Map<Integer, ColorEnum> map = new HashMap<>();  
  
    static {  
        for (ColorEnum r : ColorEnum.values()) {  
            map.put(r.getValue(), r);  
        }  
    }  
  
    ColorEnum(Integer value, String name) {  
        this.value = value;  
        this.name = name;  
    }  
  
    public static ColorEnum of(Integer value) {  
        return map.getOrDefault(value, null);  
    }  
}  

如果我想知道某个常量值x是否包含在枚举类ColorEnum 中,就可以使用of()方法:

public static void main(String[] args) {  
    System.out.println(ColorEnum.of(0) == null);  // false  
    System.out.println(ColorEnum.of(3) == null);  // true  
}  

运行结果如下:

在这里插入图片描述

3)枚举实现抽象方法

枚举中不只可以定义一些整数或是字符串常量,甚至可以重新实现抽象方法,我们定义了一个枚举类型Weekday,表示一周中的每一天。每个枚举常量都重写了抽象方法doSomething(),并实现了具体的业务逻辑,代码如下:

public enum Weekday {  
    MONDAY {  
        @Override  
        public void doSomething() {  
            System.out.println("Doing something on Monday");  
        }  
    },  
    TUESDAY {  
        @Override  
        public void doSomething() {  
            System.out.println("Doing something on Tuesday");  
        }  
    },  
    WEDNESDAY {  
        @Override  
        public void doSomething() {  
            System.out.println("Doing something on Wednesday");  
        }  
    },  
    THURSDAY {  
        @Override  
        public void doSomething() {  
            System.out.println("Doing something on Thursday");  
        }  
    },  
    FRIDAY {  
        @Override  
        public void doSomething() {  
            System.out.println("Doing something on Friday");  
        }  
    },  
    SATURDAY {  
        @Override  
        public void doSomething() {  
            System.out.println("Doing something on Saturday");  
        }  
    },  
    SUNDAY {  
        @Override  
        public void doSomething() {  
            System.out.println("Doing something on Sunday");  
        }  
    };  
  
    // 抽象方法  
    public abstract void doSomething();  
  
    public static void main(String[] args) {  
        Weekday day = Weekday.MONDAY;  
        day.doSomething();  
    }  
}  

在main函数中,通过Weekday的枚举常量来调用对应的方法,这样可以根据枚举常量来执行不同的操作,大大增加代码的可读性和可维护性。
这段代码执行结果为:

在这里插入图片描述

4)枚举注解属性

我们自定义一个名为ColorInterface的注解用于标记字段。注解定义一个value属性,类型为我们上文创建的的ColorEnum枚举类型。注解的保留策略为RetentionPolicy.RUNTIME,表示在运行时可以访问到该注解。

import java.lang.annotation.*;  
  
@Retention(RetentionPolicy.RUNTIME)  
@Target(ElementType.FIELD)  
public @interface ColorInterface {  
    ColorEnum value();  
}  

如下面代码所示,我们可以通过我们自定义的ColorInterface注解标记Flower类中的属性。main方法创建了一个Flower对象,使用反射获取Flower类中的Lily字段的注解,然后通过反射获取注解的value属性,也就是我们的枚举:

import java.lang.reflect.Field;  
  
public class Flower {  
  
    @ColorInterface(ColorEnum.BLUE)  
    private int Lily;  
  
    @ColorInterface(ColorEnum.RED)  
    private int rose;  
  
    public static void main(String[] args) throws Exception {  
        Flower flower = new Flower();  
        Field field = Flower.class.getDeclaredField("Lily");  
        ColorInterface annotation = field.getAnnotation(ColorInterface.class);  
        ColorEnum value = annotation.value();  
        System.out.println(value);  
    }  
}  

代码运行如下:

在这里插入图片描述

5)枚举实现接口

Java枚举类还可以实现接口,可以为枚举类型添加更多的方法和行为,从而扩展枚举类的功能,枚举类可以具有更多的灵活性和可扩展性此外。

public interface Animal {

    String makeSound();

    String getName();
}

public enum Dog implements Animal {
    BROWN("Buddy", "Buddy the Brown Dog"),
    BLACK("Max", "Max the Black Dog")
    ;

    private String name;
    private String sound;

    Dog(String name, String sound) {
        this.name = name;
        this.sound = sound;
    }

    @Override
    public String makeSound() {
        return sound;
    }

    @Override
    public String getName() {
        return name;
    }


    public static void main(String[] args) {
        Animal dog = Dog.BLACK;
        System.out.println(dog.getName()); // 输出: Max
        System.out.println(dog.makeSound()); // 输出: Max the Black Dog
    }

}

运行结果如下!:

在这里插入图片描述

总结

枚举类是Java中的原始类型之一,可以作为方法参数和返回值。枚举类可以通过类内的枚举常量表示特定的值。本文从源码和字节码实现的角度对枚举类的原理做了阐述,并且还展示了枚举类的多种高级用法,枚举类不仅可以像普通的类常量一样进行访问和使用,并且可以进行多态操作,不同的枚举常量可以有不同的方法实现,并且可以作为方法的参数和返回值。
因此枚举类有如下优点:
1.提高代码的可读性。枚举类的命名规范清晰明了,能够更直观地表达代码的含义,提高代码的可读性。
2.更容易的调试和维护。枚举类中的方法和变量都在一个地方,方便调试和维护。
3.更好的类型安全性。使用枚举类可以提供更好的类型安全性,避免了使用整数或其他类型的错误。
4.可以方便的进行多态操作:枚举类支持方法的重写和多态,可以方便的扩展功能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1294842.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

sfp8472学习CDR

1,cdr名称解释 因为光信号传输至一定距离的时候,通常是长距离传输,其波形会出现一定程度的失真,接收端接收到的信号是一个个长短不一的脉冲信号,这个时候在接收端,我们就无法得到我们需要的数据。所以,这个时候就需要有信号的再生,信号的再生功能为再放大、再整形和再…

全景万店通打造掌上智慧生活助手,助力店铺全景引流

随着网络经济的崛起&#xff0c;新一代的消费群体的消费习惯逐渐变得富有个性化&#xff0c;因此他们对于传统的营销方式具有视觉疲劳&#xff0c;传统广告的效果也越发微小&#xff0c;但是请明显来代言&#xff0c;成本又十分高昂&#xff0c;那么还有什么引流好方法呢&#…

c语言词法分析器

词法分析器&#xff08;也称为词法解析器或词法扫描器&#xff09;是编译器的一个组成部分&#xff0c;它的任务是将输入的源代码&#xff08;字符流&#xff09;分解成称为“标记”的序列&#xff0c;其中每个标记对应于源代码中的一个单词或符号。 以下是一个简单的C语言词法…

学习Java第64天,乱码问题

乱码问题产生的根本原因是什么 数据的编码和解码使用的不是同一个字符集 使用了不支持某个语言文字的字符集 由上图得知,上述字符集都兼容了ASCII ASCII中有什么? 英文字母和一些通常使用的符号,所以这些东西无论使用什么字符集都不会乱码 10.1.1 HTML乱码问题 设置项目…

六款好用的设备管理系统推荐

阅读本文你将了解&#xff1a;一、六款好用的设备管理系统&#xff1b;二、企业为什么要做设备管理&#xff1b;三、企业怎样选择适合自己的设备管理系统。 制造企业生产过程中对机器设备的依赖程度非常高&#xff0c;因而一系列设备巡检、维修、保养的管理需求也应运而生。设…

Spark---DataFrame存储、Spark UDF函数、UDAF函数

四、DataFrame存储Spark UDF函数 1、储存DataFrame 1&#xff09;、将DataFrame存储为parquet文件 2&#xff09;、将DataFrame存储到JDBC数据库 3&#xff09;、将DataFrame存储到Hive表 2、UDF&#xff1a;用户自定义函数 可以自定义类实现UDFX接口 java&#xff1a; …

fastadmin打印页面

如下图选中订单号进行打印 html中增加代码 <div id"toolbar" class"toolbar"><a href"javascript:;" class"btn btn-primary btn-refresh" title"{:__(Refresh)}" ><i class"fa fa-refresh">&l…

喜讯频传|海川润泽获物联网场景应用品牌企业、国家高新技术企业认定

物联网场景应用品牌企业 12月5日至6日&#xff0c;以“物联中国 数智雄安”为主题的“千企雄安行&#xff1a;2023物联网产业品牌大会”在雄安新区成功举办。大会发起了“物联网场景应用品牌企业”的评选活动&#xff0c;面向农业、城市、工业、医疗、园区、建筑、文旅、能源、…

100V耐压 3A峰值电流 60V 72V输入 输出12V 1.5A内置MOS 大电流降压芯片

100V耐压 3A峰值电流 60V 72V输入 输出12V 1.5A 内置MOS 大电流降压芯片

gitee对接使用

1.创建一个文件夹 2.进入Gitee接受对方项目编辑 3.打开终端初始化一开始创建的文件夹 git init 3.1打开终端 3.2输入git.init 4.克隆对方的项目 4.1进入Gitee复制对方项目的路径 4.2在编辑器终端内克隆对方项目 git clone 网址 如此你的编辑器就会出现对方的项目 …

公司敏感数据被上传Github,吓得我赶紧改提交记录

大家好&#xff0c;我是小富&#xff5e; 说个事吧&#xff01;最近公司发生了一个事故&#xff0c;有同事不小心把敏感数据上传到了GitHub上&#xff0c;结果被安全部门扫描出来了。这件事导致公司对所有员工进行了一次数据安全的培训。对于这个事我相信&#xff0c;有点工作…

106.进程控制(结束、孤儿、僵尸进程)以及进程回收

目录 结束进程 孤儿进程 僵尸进程 进程回收 wait() waitpid 进程控制是指在操作系统中对进程进行创建、终止、挂起、唤醒以及进程之间的同步、通信等操作的管理。 结束进程 exit() 和 _exit() 函数都用于终止一个进程&#xff0c;但它们之间有一些重要的区别&#xf…

OpenAI的Sam Altman,获《时代》2023年度最佳CEO

12月7日&#xff0c;《时代》周刊在官网公布了2023年最佳CEO——OpenAI的Sam Altman。 此外&#xff0c;梅西入选了年度最佳运动员&#xff0c;Taylor Swift入选年度最佳人物&#xff0c;Alex Newell获年度突破奖。 《时代》周刊曾在今年的9月8日发布了“2023年AI领域最有影响…

Stable Diffusion XL on diffusers

Stable Diffusion XL on diffusers 翻译自&#xff1a;https://huggingface.co/docs/diffusers/using-diffusers/sdxl v0.24.0 非逐字翻译 Stable Diffusion XL (SDXL) 是一个强大的图像生成模型&#xff0c;其在上一代 Stable Diffusion 的基础上主要做了如下优化&#xff1a;…

超详细介绍Ubuntu系统安装CUDA和cuDNN【一站式服务!!!】

文章目录 简介1.安装显卡驱动查看显卡型号下载并安装NVIDIA驱动使用Ubuntu自带的软件和更新&#xff08;Software&Updates&#xff09;工具安装【博主使用的这种方式&#xff0c;推荐】自行下载使用命令行安装【自由度更高&#xff0c;大佬自行尝试】 2.下载并安装CUDA3.下…

docker容器_自定义上传jenkins镜像(Dockerfile实现)

1.创建jenkins目录&#xff0c;并上传相应的包 mkdir /jenkins/ 2.创建一个Dockerfile文件 FROM daocloud.io/library/centos:7#把当前目录下的jenkins.war包传到内部容器的/ 下 ADD ./jenkins.war /#把当前目录下的jdk传到内部容器的/opt/,并解压 ADD ./jdk-11.0.19_linu…

【软件推荐】文本转语音,语音转wav,导入ue5

文字转语音 在线免费文字转语音 - TTSMaker官网 | 马克配音https://ttsmaker.cn/ 文件转换器 语音转wav Convertio — 文件转换器https://convertio.co/zh/

前端学习微信小程序开发

1.微信小程序项目结构 2.WXML和HTML的区别 3.WXSS与CSS的区别 4.小程序中的.js文件 5.小程序的宿主环境 宿主环境是指程序运行所必须的依赖环境&#xff0c;因此手机微信时小程序的宿主环境。小程序宿主环境包含了通信模型、运行机制、组件、API。 &#xff08;1&#xff09;…

基于jsp+servlet的图书管理系统

基于jspservlet的图书管理系统演示地址为 图书馆后台管理系统 用户名:mr ,密码:123 图书馆管理系统主要的目的是实现图书馆的信息化管理。图书馆的主要业务就是新书的借阅和归还&#xff0c; 因此系统最核心的功能便是实现图书的借阅和归还。此外&#xff0c;还需要提供图书…

小视频怎么做成二维码?视频二维码3步生成

在日常工作和生活中经常会看到各种类型的小视频、短视频&#xff0c;比如网页、抖音等等的视频都是可以下载查看的。当我们想要将下载视频分享给多个人看时&#xff0c;生成二维码的方式会更加的方便&#xff0c;那么视频如何生成二维码呢&#xff1f;下面就将快捷生成二维码的…