【Java】深入剖析Java枚举类

在这里插入图片描述

目录

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

定义

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;}@Overridepublic String makeSound() {return sound;}@Overridepublic String getName() {return name;}public static void main(String[] args) {Animal dog = Dog.BLACK;System.out.println(dog.getName()); // 输出: MaxSystem.out.println(dog.makeSound()); // 输出: Max the Black Dog}}

运行结果如下!:

在这里插入图片描述

6)复合使用

前面的这些特性当然可以混在一起使用:

我们定义一个接口 Reflex ,里面实现了两个方法,一个是可以返回颜色名称,一个是可以以List形式返回它的RGB值


import java.util.List;public interface Reflex {String getColor();List<Integer> getRGB();
}

然后我们重新写一下我们的 ColorEnum 枚举类,里面的枚举常量对象既包含属性值,又重写了方法,功能比之前更强大了一些,代码如下:


import lombok.Getter;import java.util.HashMap;
import java.util.List;
import java.util.Map;public enum ColorEnum implements Reflex {RED(0, "红色") {@Overridepublic List<Integer> getRGB() {return List.of(255, 0, 0);}},BLUE(1, "蓝色") {@Overridepublic List<Integer> getRGB() {return List.of(0, 0, 255);}},GREEN(2, "绿色") {@Overridepublic List<Integer> getRGB() {return List.of(0, 255, 0);}},;// 重写Reflex接口方法@Overridepublic String getColor() {return name;}@Getter  private Integer value;  @Getterprivate 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);  }public static void main(String[] args) {ColorEnum colorEnum1 = ColorEnum.of(2);System.out.println(colorEnum1.getName());System.out.println(colorEnum1.getColor());System.out.println(colorEnum1.getRGB());}
}  

main()运行结果为:

在这里插入图片描述
可以看到,我们既返回了枚举的属性值,又返回了重写方法的返回值,枚举是否有其它高级用法,也欢迎探索交流讨论

总结

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

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

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

相关文章

LeetCode 309买卖股票的最佳时机含冷冻期 714买卖股票的最佳时机含手续费 | 代码随想录25期训练营day51

动态规划算法9 LeetCode 309 买卖股票的最佳时机含冷冻期 2023.12.14 题目链接代码随想录讲解[链接] int maxProfit(vector<int>& prices) {//1确定dp二维数组//dp[i][0]表示遍历到第i天时持有股票的当前收入;dp[i][1]表示遍历到第i天时未持有股票的当前收入//dp…

网页图标素材免费下载网站

这里是几个可以免费下载网页图标素材的的网站。这些个网站里的图表和素材&#xff0c;应该是都可以免费下载的。&#xff08;至少我下载了几个素材是没有花钱的&#xff09; Flaticon iconArchive freepik 4. iconmonstr 5. Icons and Photos For Everything 如果想下载图片&a…

idea中定时+多数据源配置

因项目要求,需要定时从达梦数据库中取数据,并插入或更新到ORACLE数据库中 1.pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-…

centos7服务器上的文件上传到谷歌云盘(google drive)

1,下载gdrive客户端&#xff0c;Releases glotlabs/gdrive GitHub 2&#xff0c;下载完解压,并移动到cp gdrive /usr/local/bin/ 3&#xff0c;查看是否安装成功 4,添加账户&#xff0c;gdrive account add 根据链接&#xff0c;创建Client id和 Client secret 5,填写Client…

QT-ClementineMusierPlaey音乐播放器

QT-ClementineMusierPlaey音乐播放器 一、效果二、下载链接 一、效果 二、下载链接 https://download.csdn.net/download/u013083044/88629413

致远互联-OA wpsAssistServlet 任意文件读取漏洞复现

0x01 产品简介 致远互联-OA 是数字化构建企业数字化协同运营中台,面向企业各种业务场景提供一站式大数据分析解决方案的协同办公软件。 0x02 漏洞概述 致远互联-OA wpsAssistServlet 存在任意文件读取漏洞,攻击者可读取系统密码等敏感信息进一步控制系统。 0x03 复现环境…

整理b站黑马程序员C++课程中对于计算机视觉学习有所帮助的知识点。(重点用*标出)

文章目录 1、注释2、变量3、常量4、标识符5、整型 浮点型 字符型 字符串 布尔6、输入 输出7、逻辑运算法8、 程序流程结构9、三目运算符10、switch语句11、循环语句12、跳转语句13、*数组13.1一维数组名 14、二维数组15、**函数15.1、函数的调用15.2、函数的声明15.3、函数份文…

VMware安装Windows V10

一、安装Windows系统 1.下载Windows IOS 镜像文件 Windows官网 1&#xff09;点击下载工具 2&#xff09;点击 MediaCreationTool22H2.exe 运行 3&#xff09;选择&#xff1a;为另一台电脑创建安装介质&#xff08;U盘、DVD或者ISO文件&#xff09; 4&#xff09;根据自身…

Flink的容错机制

容错机制 容错&#xff1a;指出错后不影响数据的继续处理&#xff0c;并且恢复到出错前的状态。 检查点&#xff1a;用存档读档的方式&#xff0c;将之前的某个时间点的所有状态保存下来&#xff0c;故障恢复继续处理的结果应该和发送故障前完全一致&#xff0c;这就是所谓的检…

纳米软件分享:电源自动测试系统是什么?有什么特点和优势?

随着技术的发展以及测试需求的严格性&#xff0c;一种新的、利用软硬件结合的自动化测试方式油然而生。 电源自动测试系统是一种用于电子与通信技术领域的电子测量仪器&#xff0c;可以提供众多变化的硬件选择&#xff0c;满足产品升级所带来的新的测试要求。电源自动测试系统通…

Windows ❀ 关闭Google的自动更新功能

文章目录 1. 故障问题2. 解决方法 1. 故障问题 如何关闭掉Google的自动更新功能&#xff1f; 2. 解决方法 修改更新域名本地hosts为环回地址即可。 # 禁止google自动更新 127.0.0.1 update.googleapis.com备注&#xff1a; mac路径&#xff1a;/etc/hostswindows路径&…

Ansible介绍与安装

Ansible目前是运维自动化工具中最简单、容易上手的一款优秀软件&#xff0c;能够用来管理各种资源。用户可以使用Ansible自动部署应用程序&#xff0c;以此实现IT基础架构的全面部署。例如&#xff0c;借助于Ansible&#xff0c;我们可以轻松地对服务器进行初始化配置、安全基线…

IDEA中显示方法、类注释信息

目录 一、IDEA测试版本及环境二、操作步骤2.1 鼠标悬停在某一个方法上&#xff0c;从而显示方法的注释信息2.2 调用方法时同步显示方法注释信息2.3 在new一个对象时&#xff0c;这个对象有很多重载的构造方法&#xff0c;想要重载的构造函数都显示出来 一、IDEA测试版本及环境 …

LeetCode刷题--- 二叉搜索树中第K小的元素

个人主页&#xff1a;元清加油_【C】,【C语言】,【数据结构与算法】-CSDN博客 个人专栏 力扣递归算法题 【 http://t.csdnimg.cn/yUl2I 】【C】 【 http://t.csdnimg.cn/6AbpV 】数据结构与算法 【 http://t.csdnimg.cn/hKh2l 】 前言&#…

在IDEA中配置Git的Push键

前言 笔者在重新安装IDEA过程中需要重新绑定了Git&#xff0c;发现提交代码过程中push键消失了&#xff0c;所以笔者就以这篇文章记录一下Git配置push键的详细过程。 注意笔者当前IDEA版本为2019&#xff0c;可能和读者有所区别&#xff0c;但是操作思路是差不多的。 操作步…

推荐域名销售管理系统网站源码

域名销售管理系统网站源码是一个完整的网站开发项目&#xff0c;包含了域名销售管理的各项功能&#xff0c;如域名搜索、购买、转让、续费等。源码采用了先进的技术和设计&#xff0c;能够满足用户的各种需求&#xff0c;是一个高效、稳定的域名销售管理系统。 演示地 址 &…

使用ThreadLocal.withIniti避免初始化为null问题

问题描述 我们在使用threadLocal的时&#xff0c;使用ThreadLocal.withInitial去初始化而不是使用new ThradLocal去初始化&#xff0c;这是为什么呢&#xff1f; 问题例子 比如说&#xff0c;假设我们想要在每个线程中维护一个独立的计数器 import java.util.concurrent.at…

【EI会议征稿】第五届机械仪表与自动化国际学术会议(ICMIA 2024)

第五届机械仪表与自动化国际学术会议&#xff08;ICMIA 2024&#xff09; The 5th International Conference on Mechanical Instrumentation and Automation 2024年第五届机械仪表与自动化国际学术会议&#xff08;ICMIA 2024&#xff09;定于2024年4月5-7日在中国武汉隆重…

BUUCTF-[GYCTF2020]FlaskApp flask爆破pin

这道题不需要爆破也可以getshell ssti都给你了 {{((lipsum.__globals__.__builtins__[__import__](so[::-1])[popen]("\x63\x61\x74\x20\x2f\x74\x68\x69\x73\x5f\x69\x73\x5f\x74\x68\x65\x5f\x66\x6c\x61\x67\x2e\x74\x78\x74")).read())}} 但是学习记录一下pin…

【数据结构】栈和队列超详解!(Stack Queue)

文章目录 前言一、栈1、栈的基本概念2、栈的实现&#xff08;数组实现&#xff09;3、栈的基本操作3.1 栈的结构设计3.2 栈常见的基本函数接口 4、栈的实现4.1 初始化栈4.2 栈的销毁4.3 入栈4.4 出栈4.5 判空4.6 长度4.7 获取栈顶元素 完整代码Stack.hStack.cTest.c 二、队列1、…