Java 枚举

目录

枚举是什么

常用方法

构造方法

枚举的优缺点

枚举和反射

实现单例模式


枚举是什么

枚举(enum):是一种特殊的类,用于定义一组常量,将其组织起来。枚举使得代码更具有可读性和可维护性,特别是在处理固定集合的值时,如:星期、月份、状态码等

在 Java 中,使用关键字 enum 来定义枚举类:

public enum Day {
    SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY;
}

其中,定义的枚举项就是该类的实例,且必须在第一行,最后一个枚举项后的分号; 可以省略,但是若枚举类有其他内容,则分号不能省略(最好不要省略) 

当类初始化时,这些枚举项就会被实例化

枚举类使用 enum 定义后,默认继承 java.lang.Enum 类,也就是说,我们自己写的枚举类,就算没有显示的继承 Enum,但是其默认继承了这个类

此外,枚举在 Java 中不能被继承,自定义的枚举类隐式继承自 java.lang.Enum 类,且不能再继承其他类,这样的设计确保了枚举类的简单性和一致性。如果枚举可以继承其他类,将会导致复杂的继承关系,并且影响Java的类型系统

常用方法

方法描述
values()以数组的形式返回枚举类型的所有成员

ordinal()

获取枚举成员的索引位置
valueOf()将普通字符串转换为枚举实例

compareTo(E o)

比较两个枚举成员在定义时的顺序

 我们通过一个示例,来学习和使用这些方法:

public enum Day {
    SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY;

    public static void main(String[] args) {
        // 获取所有枚举成员
        Day[] days = Day.values();
        // 遍历
        for (int i = 0; i < days.length; i++) {
            // 获取枚举成员以及索引位置
            System.out.println(days[i] + " " + days[i].ordinal());
        }
        // 将普通字符串转换为枚举实例
        System.out.println(Day.valueOf("THURSDAY"));
        // 获取枚举实例 SUNDAY 和 SATURDAY
        Day sunday = Day.SUNDAY;
        Day saturday = Day.SATURDAY;
        // 比较定义时的顺序
        System.out.println(sunday.compareTo(saturday));

    }
}

运行结果:

在使用 valueOf() 方法进行转换时,传递的名称必须与枚举常量的名字完全匹配(包括大小写),若不匹配,就会抛出 IllegalArgumentException 异常:

 当我们查看 java.lang.Enum 时:

可以看到,valueOf() 方法包含了两个类型的参数:Class<T> enumClass  和  String name

其中

Class<T> enumType 是一个 Class 对象,表示要查找的枚举类型

String name: 是一个字符串,表示要查找的枚举常量的名称。名称必须与枚举常量的名字完全匹配(包括大小写)

 但是在使用时,我们只传递了一个参数 name,也能够进行转换,这是为什么呢?

这是因为,在 Java 中,valueOf 方法实际上是自动生成的属于每个枚举类型的特性。虽然它的原始定义需要两个参数(类类型和名称),但是每个枚举类型都会自动提供一个与自身类型相关联的 valueOf 方法,只需传递一个字符串参数

因此,当我们调用 Day.valueOf("THURSDAY") 时,Java会自动处理这个调用,实际调用的是包含类名的 valueOf 方法,而不是原始的静态方法定义

再观察 java.lang.Enum:

我们会发现,其中并不存在 values() 这个方法,而当我们点击 values() 方法时,则会跳转到本类上

那么,values() 方法是从哪来的呢?

values() 方法是枚举类自动提供的一个静态方法,允许我们获取一个包含所有枚举常量的数组,这个方法是由Java编译器自动生成的,在编译时每个枚举类型都会自动生成一个 values() 方法,因此不需要我们显式定义它

我们将枚举类进行反编译:

(1)打开 cmd,切换到 Day.java 文件所在目录

(2)编译 .java 文件(javac Day.java)

(3)将 .class 文件进行反编译(javap -c Day.class > day.txt)

打开 day.txt,可以看到:

编译器自动为我们生成了 values 和 valueOf 方法

构造方法

当我们创建构造方法时:

 不能使用 public 来修饰构造方法,为什么呢?

这是因为,在 Java 中,枚举类的构造方法都是私有的(不加任何修饰符时,默认是 private),无法在枚举类外部调用,这也就防止了在枚举类外部创建新的枚举常量

在定义枚举常量时,构造方法会被隐式调用:

public enum Day {
    SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY;

    Day() {
        System.out.println("构造方法");
    }

    public static void main(String[] args) {
        System.out.println("------------------");
    }
}

运行结果: 

 当我们定义带有参数的构造方法时,在创建枚举项时,也要为其提供对应参数:

public enum Day {
    SUNDAY("周天", 7),
    MONDAY("周一", 1),
    TUESDAY("周二", 2),
    WEDNESDAY("周三", 3),
    THURSDAY("周四", 4),
    FRIDAY("周五", 5),
    SATURDAY("周六", 6);
    private String name;
    private int key;

    Day(String name, int key) {
        this.name = name;
        this.key = key;
    }
}

枚举的优缺点

优点:

(1)枚举常量确保了只能使用定义的常量,避免了使用整型常量时可能带来的错误

(2)使用枚举可以使代码更易读,表达清晰

(3)枚举定义了一组固定的常量,适合表示有限的状态或选项,便于管理和维护

(4)枚举可以拥有字段、方法和构造方法,能够封装与常量相关的行为和属性

(5)Java的枚举类自带一些方法,如 values()、valueOf() 等

(6)可以用于 switch 语句

缺点:

(1)枚举的集合是固定的,无法在运行时添加或删除常量。如果需要动态的集合,枚举可能不适用

(2)枚举不能继承,无法扩展

(3)每个枚举常量都是一个对象,可能会增加内存使用,特别是当枚举常量数量较多时

枚举和反射

在 Java 反射-CSDN博客 中,我们学习了反射,通过反射,我们可以拿到类的私有构造方法,从而创建实例对象

那么,枚举是否可以通过反射,拿到实例对象呢?

public enum Day {
    SUNDAY("周天", 7),
    MONDAY("周一", 1),
    TUESDAY("周二", 2),
    WEDNESDAY("周三", 3),
    THURSDAY("周四", 4),
    FRIDAY("周五", 5),
    SATURDAY("周六", 6);
    private String name;
    private int key;

    Day(String name, int key) {
        this.name = name;
        this.key = key;
    }
}
public class Test {
    public static void main(String[] args) {
        Class<?> classDay = null;
        try {
            classDay = Class.forName("Day");
            Constructor<?> constructor = classDay.getDeclaredConstructor(String.class, int.class);
            constructor.setAccessible(true);
            Day day = (Day) constructor.newInstance("sunday", 0);
            System.out.println(day.ordinal());
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
}

运行结果:

此时程序抛出了 NoSuchMethodException 异常,也就是没有对应的构造方法

但是提供的枚举的构造方法就是带有两个参数,分别为 String 和 int:

那么,问题出在哪里呢?

自定义的枚举类默认继承自 java.lang.Enum

因此,自定义的枚举类继承了父类除构造方法外的所有东西,且子类需要帮助父类进行构造,

但我们实现的类中,并没有帮助父类进行构造

因此,我们需要在枚举类中帮助父类进行构造,而父类中的构造方法为:

那么,如何实现呢?通过 super 方法吗?

但是,当我们在构造方法中调用 super 时:

枚举构造方法中不能使用 super

 由于枚举比较特殊,在构造方法中,除了我们自定义了两个参数,它还默认添加了父类的两个参数

也就是说,构造函数中一共有四个参数:String int String int

其中,前两个参数是父类参数,后两个参数是子类参数

public class Test {
    public static void main(String[] args) {
        Class<?> classDay = null;
        try {
            classDay = Class.forName("enumDemo.Day");
            Constructor<?> constructor = classDay.getDeclaredConstructor(String.class, int.class, String.class, int.class);
            constructor.setAccessible(true);
            Day day = (Day) constructor.newInstance("父类参数", 0, "子类参数", 0);
            System.out.println(day.ordinal());
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
}

再次运行:

此时抛出了 IllegalArgumentException 异常,不能通过反射创建枚举对象

枚举保证了每个枚举常量只有一个实例,这种唯一性在枚举类型被定义时就已经确定,不允许外部创建新的实例,枚举类型的设计使得它们的实例在类加载时被唯一地定义,从而避免了通过反射创建新的枚举实例的可能性,确保了枚举的强类型安全性和唯一性

实现单例模式

在 单例模式:饿汉模式、懒汉模式_单例模式懒汉和饿汉-CSDN博客 中我们实现了单例模式,单例模式能够确保一个类只有一个实例

但普通类可以通过反射机制打破,因此,我们可以使用枚举来实现单例模式

public enum Singleton {
    INSTANCE;
    public Singleton getInstance() {
        return INSTANCE;
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

服务器限制某个端口只允许特定IP访问(处理第三方依赖漏洞)

最近项目部署之后&#xff0c;有些客户开始进行系统系统漏洞扫描&#xff0c;其中出现问题多的一个就是我们项目所依赖的Elasticsearch&#xff08;es检索服务&#xff09;&#xff0c;很容易就被扫出来各种高危漏洞&#xff0c;而且这些漏洞我们在处理起来是很棘手的&#xff…

安卓 文件管理相关功能记录

文件管理细分为图片、视频、音乐、文件四类 目录 权限 静态声明权限 动态检查和声明权限方法 如何开始上述动态申请的流程 提示 图片 获取图片文件的对象列表 展示 删除 视频 获取视频文件的对象列表 获取视频file列表 按日期装载视频文件列表 展示 播放 删除…

Springmvc初学

什么是springmvc springmvc框架它是spring框架的一个分支。它是按照mvc架构思想设计的一款框架。springmvc的主要作用: 接收浏览器的请求数据&#xff0c;对数据进行处理&#xff0c;然后返回页面进行显示。 为什么要学习springmvc 如何使用springmvc&#xff1f; 1.创建maven…

知从科技总经理受邀参加上海临港新片区商会“湖畔TECS”技术分享沙龙(第五期)

11月26日&#xff0c;上海知从科技有限公司创始人陈荣波先生受邀出席临港新片区商会 “湖畔TECS”技术分享沙龙&#xff08;第五期&#xff09;活动&#xff0c;并在活动上为参会嘉宾们做了主题分享。本次活动由临港新片区商会主办&#xff0c;智能网联汽车创新联盟协办&#x…

Vue中纯前端实现导出简单Excel表格的功能

Vue 前端Excel导出 Vue中纯前端导出简单Excel表格的方法(使用vue-json-excel插件) 前言 在许多的后台系统中少不了导出Excel表格的功能&#xff0c;在项目中纯前端使用vue-json-excel插件来实现简单Excel表格的导出功能。 使用方法 1、安装依赖 npm install vue-json-exc…

QT6 Socket通讯封装(TCP/UDP)

为大家分享一下最近封装的以太网socket通讯接口 效果演示 如图&#xff0c;界面还没优化&#xff0c;后续更新 废话不多说直接上教程 添加库 如果为qmake项目中&#xff0c;在.pro文件添加 QT network QT core gui QT networkgreaterThan(QT_MAJOR_VERS…

ip_done

文章目录 路由结论 IP分片 数据链路层重谈Mac地址MAC帧报头局域网的通信原理MSS&#xff0c;以及MAC帧对上层的影响ARP协议 1.公司是不是这样呢? 类似的要给运营商交钱&#xff0c;构建公司的子网&#xff0c;具有公司级别的入口路由器 2&#xff0e;为什么要这样呢?? IP地…

LearnOpenGL学习(高级OpenGL -> 高级GLSL,几何着色器)

完整代码见&#xff1a;zaizai77/Cherno-OpenGL: OpenGL 小白学习之路 高级GLSL 内建变量 顶点着色器 gl_PointSoze : float 输出变量&#xff0c;用于控制渲染 GL_POINTS 型图元时&#xff0c;点的大小。可用于粒子系统。将其设置为 gl_Position.z 时&#xff0c;可以使点…

vscode设置终端代理

转载请标明出处&#xff1a;小帆的帆的博客 设置终端代理 修改项目的.vscode/settings.json {"terminal.integrated.env.windows": {"http_proxy": "http://127.0.0.1:7890","https_proxy": "http://127.0.0.1:7890"}, }…

计算机视觉中的边缘检测算法

摘要&#xff1a; 本文全面深入地探讨了计算机视觉中的边缘检测算法。首先阐述了边缘检测的重要性及其在计算机视觉领域的基础地位&#xff0c;随后详细介绍了经典的边缘检测算法&#xff0c;包括基于梯度的 Sobel 算子算法、Canny 边缘检测算法等&#xff0c;深入剖析了它们的…

ComfyUI 与 Stable Diffusion WebUI 的优缺点比较

ComfyUI与Stable Diffusion WebUI都是AI绘画领域比较知名两款产品&#xff0c;两者存在诸多差异&#xff0c;本篇就带你熟悉二者的优劣&#xff0c;方便自己做出决策。 界面与操作 ComfyUI&#xff1a;界面简洁直观&#xff0c;通过节点和连线的方式构建工作流&#xff0c;用…

2024年12月16日Github流行趋势

项目名称&#xff1a;PDFMathTranslate 项目维护者&#xff1a;Byaidu reycn hellofinch Wybxc YadominJinta项目介绍&#xff1a;基于 AI 完整保留排版的 PDF 文档全文双语翻译&#xff0c;支持 Google/DeepL/Ollama/OpenAI 等服务&#xff0c;提供 CLI/GUI/Docker。项目star数…

CDGA|“数据池塘资源”理论的出现对数据治理有怎样的影响?

“数据池塘资源”这一理论实践&#xff0c;可以理解为将数据集视为一个池塘&#xff0c;其中蕴含着丰富的信息和资源&#xff0c;有待于人们去挖掘和利用。这一理论实践对数据管理、分析和应用等领域可能会产生一系列深远的影响。以下是对其可能影响的详细分析&#xff1a; 一、…

linux学习笔记02 linux中的基础设置(修改主机名、ip、防火墙、网络配置管理)

目录 修改主机名 ​编辑 修改ip地址 防火墙 关闭networkmanage 修改主机名 查看主机名 hostnamectl status 修改主机名 vim /etc/hostname 修改ip地址 vim /etc/sysconfig/network-scripts/ifcfg-ens33 输入这个命令后对照以下文件修改 TYPE"Ethernet" PROXY_M…

用户发送请求后服务端i/o工作过程

华子目录 服务端i/o介绍磁盘i/o机械磁盘的寻道时间、旋转延迟和数据传输时间常见的机械磁盘平均寻道时间值常见磁盘的平均延迟时间每秒最大IOPS的计算方法 网络i/o网络I/O处理过程磁盘和网络i/o 一次完整的请求在内部的执行过程 服务端i/o介绍 i/o在计算机中指Input/Output&am…

240004基于Jamva+ssm+maven+mysql的房屋租赁系统的设计与实现

基于ssmmavenmysql的房屋租赁系统的设计与实现 1.项目描述2.运行环境3.项目截图4.源码获取 1.项目描述 该项目在原有的基础上进行了优化&#xff0c;包括新增了注册功能&#xff0c;房屋模糊查询功能&#xff0c;管理员和用户信息管理等功能&#xff0c;以及对网站界面进行了优…

MinerU(2):GPU加速

目录 遗留问题&#xff1a;ubuntu使用特定conda环境CUDA加速速度对比 解析效果公式解析表格解析实验结论 遗留问题&#xff1a;ubuntu使用特定conda环境 发现在vscode中能查看到版本&#xff0c; 但是到虚拟机&#xff0c;同样的目录下查不到 可能是vscode能自己切换Python环…

C# 生成随机数的方法

C# 提供了一种强大而方便的工具类 Random &#xff0c;用于生成随机数。这里将分类讨论如何通过 C# 实现随机数生成&#xff0c;以及应用于实际情况中的一些具体方案。 一、Random 类概述 Random 类表示一个伪随机数生成器&#xff0c;用于生成满足随机性统计要求的数字序列。…

wazuh-modules-sca-scan

sca模块主函数wm_sca_main -> wm_sca_start 检查policy文件中的每一个项目wm_sca_check_policy static int wm_sca_check_policy(const cJSON * const policy, const cJSON * const checks, OSHash *global_check_list) {if(!policy) {return 1;}const cJSON * const id c…

SpringCloud微服务实战系列:03spring-cloud-gateway业务网关灰度发布

目录 spring-cloud-gateway 和zuul spring webflux 和 spring mvc spring-cloud-gateway 的两种模式 spring-cloud-gateway server 模式下配置说明 grayLb://system-server 灰度发布代码实现 spring-cloud-gateway 和zuul zuul 是spring全家桶的第一代网关组件&#x…