通俗易懂理解Java枚举类

news/2024/9/19 4:47:28/ 标签: java, 枚举

什么是枚举

一组常量

比如一年的 4 个季节,一年的 12 个月份,一个星期的 7 天,方向有东南西北等。

Java 枚举类使用 enum 关键字来定义,各个常量使用逗号 , 来分割。

例如定义一个颜色的枚举类。

enum Color 
{ RED, GREEN, BLUE; 
} 

这时候一定有人会说,常量直接用static final来定义来定义不就好了,花里胡哨的搞个额外的枚举类有什么意义?

static final定义常量存在的问题

例如,定义3种颜色的常量:

public class Color {public static final String RED = "r";public static final String GREEN = "g";public static final String BLUE = "b";
}

使用常量的时候,可以这么引用:

String color = ...
if (Color.RED.equals(color)) {// TODO:
}

这样存在最大的问题:

编译器无法检查每个值的合理性

也就是我这里的color我想写什么字符串都可以。那这样我定义一个String color = “想写什么都行”,拿这种乱七八糟的值进行比较是没有任何意义的,但是程序依然不会在编译的时候给你提示有异常。

我们如果用枚举,就可以避免这种潜在的错误。

枚举代替static final定义常量

为了让编译器能自动检查某个值在枚举的集合内,并且,不同用途的枚举需要不同的类型来标记,不能混用,我们可以使用enum来定义枚举类:

public enum Color {RED, GREEN, BLUE
}

和String定义的常量相比,使用enum定义枚举有如下好处:

  • 首先,enum常量本身带有类型信息,即Color.RED类型是Color,编译器会自动检查出类型错误。例如,下面的语句不可能编译通过:
    在这里插入图片描述

  • 其次,不可能引用到非枚举的值,因为无法通过编译。

这就使得编译器可以在编译期自动检查出所有可能的潜在错误。

enum和class区别

enum本质就是class,只不过是特殊的class,和其它class相比它有如下特点:

  • 定义的enum类型总是继承自java.lang.Enum,且无法被继承;
  • 只能定义出enum的实例,而无法通过new操作符创建enum的实例;
  • 定义的每个实例都是引用类型的唯一实例;
  • 可以将enum类型用于switch语句。

这个时候有人又要问了:你说enum就是class,为什么我定义一个类的时候,一般都得写成员变量、构造方法等,定义枚举比如下面这种,里面就写了几个用逗号分隔的大写“单词”?

public enum Color {RED, GREEN, BLUE;
}

是的,我们直接看编译器编译出来后的结果:

public final class Color extends Enum { // 继承自Enum,标记为final class// 每个实例均为全局唯一:public static final Color RED = new Color();public static final Color GREEN = new Color();public static final Color BLUE = new Color();// private构造方法,确保外部无法调用new操作符:private Color() {}
}

这么一看是不是就明白了:

  1. Color类是final的,就不能继成
  2. 构造方法的private的,就不能new
  3. 所谓大写的“单词”,其实就是Color唯一对象

所以,枚举就是在类基础上做了一些小小的改动,其实它就是类。枚举还有一些内置的方法。

枚举常用的方法

  1. values()返回枚举类中所有的值。
  2. ordinal()可以找到每个枚举常量的索引,就像数组索引一样。
  3. valueOf()方法返回指定字符串值的枚举常量。
  • 示例

            // 调用 values()Color[] arr = Color.values();// 迭代枚举for (Color col : arr) {// 查看索引System.out.println(col + " at index " + col.ordinal());}// 使用 valueOf() 返回枚举常量,不存在的会报错 IllegalArgumentExceptionSystem.out.println(Color.valueOf("RED"));// System.out.println(Color.valueOf("WHITE"));
    
  • 结果:

    RED at index 0
    GREEN at index 1
    BLUE at index 2
    RED
    

我们在使用ordinal方法的时候可能会有一个疑问:ordinal()可以找到每个枚举常量的索引,就像数组索引一样。但是如果不小心修改了枚举的顺序,编译器是无法检查出这种逻辑错误的,这是不是很危险吗?

的确是这样的,使用这个方法有个前提:我们认为枚举顺序的不会改变的。

但是程序是很多人在开发,谁也无法保证,我们在新增枚举的时候,每次都放在最后。

要编写健壮的代码,就不要依靠ordinal()的返回值。因为enum本身是class,所以我们可以定义private的构造方法,并且,给每个枚举常量添加字段,接下来我们看看详细操作。

枚举常量加字段

枚举跟普通类一样可以用自己的变量、方法和构造函数,构造函数只能使用 private 访问修饰符,所以外部无法调用。

枚举既可以包含具体方法,也可以包含抽象方法。 如果枚举类具有抽象方法,则枚举类的每个实例都必须实现它。

因此,我们这里说的给枚举常量加字段,说白了,就是给类加成员方法。

public enum Color {RED(255, 0, 0),GREEN(0, 255, 0),BLUE(0, 0, 255);private int red;private int green;private int blue;// 私有的构造方法Color(int red, int green, int blue) {this.red = red;this.green = green;this.blue = blue;}// 获取颜色值的方法public int getRed() {return red;}public int getGreen() {return green;}public int getBlue() {return blue;}
}

那么比如有其它人想要在这个枚举类中新增一个白色,那么他可以放在任何位置:

public enum Color {RED(255, 0, 0, 0),WHITE(0, 0, 0, 255),GREEN(0, 255, 0, 0),BLUE(0, 0, 255, 0);private int red;private int green;private int blue;private int white;// 私有的构造方法Color(int red, int green, int blue, int white) {this.red = red;this.green = green;this.blue = blue;this.white = white;}// 获取颜色值的方法public int getRed() {return red;}public int getGreen() {return green;}public int getBlue() {return blue;}public int getWhite() {return white;}
}

我们可以测试一下:

  • 测试代码:

            Color[] arr = Color.values();for (Color col : arr) {// 查看索引System.out.println(col + " at index " + col.ordinal());}System.out.println(Color.valueOf("WHITE"));
    
  • 结果:

    RED at index 0
    WHITE at index 1
    GREEN at index 2
    BLUE at index 3
    WHITE
    

在 switch 中使用枚举

枚举类可以应用在switch语句中。因为枚举类天生具有类型信息和有限个枚举常量,所以比int、String类型更适合用在switch语句中。

  • 代码

    public class TestColor {public static void main(String[] args) {Color myColor = Color.RED;switch (myColor) {case RED:System.out.println("红色");break;case GREEN:System.out.println("绿色");break;case BLUE:System.out.println("蓝色");break;}}
    }
    
  • 结果

    红色
    

参考文献

  1. https://www.geeksforgeeks.org/enum-in-java/
  2. https://www.geeksforgeeks.org/enum-customized-value-java/
  3. https://liaoxuefeng.com/books/java/oop/core/enum/index.html
  4. https://www.runoob.com/java/java-enum.html

http://www.ppmy.cn/news/1520617.html

相关文章

C++菜鸟教程 - 从入门到精通 第一节

一.C简介 C 是一种编程语言,它是由 Bjarne Stroustrup 于 1979 年在贝尔实验室开始设计开发的。C 进一步扩充和完善了 C 语言,是一种面向对象的程序设计语言。C 可运行于多种平台上,如 Windows、MAC 操作系统以及 UNIX 的各种版本。 C 是一种…

MongoDB之MongoDB Compass工具

MongoDB Compass 是 MongoDB 官方提供的一款图形化用户界面 (GUI) 工具,用于与 MongoDB 数据库进行交互和管理。Compass 提供了丰富的功能,能够帮助开发者、数据库管理员以及数据分析师轻松管理和分析 MongoDB 数据。以下是对 MongoDB Compass 的详细介绍…

Go语言 Go程基础

本篇文章主要为Go语言 Go程基础内容介绍及代码示例。 目录 并发与并行 Go程介绍 简单go程示例 匿名函数写法 启动多个子go进程 总结 并发与并行 并发:电脑同时听歌,看小说,看电影。cpu根据时间片进行划分,交替执行这个三个…

Windows安装docker,启动ollama运行open-webui使用AIGC大模型写周杰伦歌词

Windows安装docker,启动ollama运行open-webui使用AIGC大模型写周杰伦歌词 1、下载docker的Windows版本。 docker下载地址: https://docs.docker.com/desktop/install/windows-install/https://docs.docker.com/desktop/install/windows-install/ 2、设…

java基础知识-JVM知识详解

一、JVM内存结构 Java虚拟机(JVM)的内存结构主要分为几个不同的区域,每个区域都有其特定的目的和功能。以下是JVM内存结构的主要组成部分: 先看一下总体的结构图 程序计数器(Program Counter Register) 这是一个较小的内存块,用于存储当前线程所执行的字节码指令的地址…

tomato靶机通关攻略

主机发现 用kali去扫描端口,发现有3个开放端口 访问网站 在kali里面进行目录扫描,找到一个antibot_image 找到一个/antibot_image/ 目录,进而找到/antibots/目录 发现可能存在文件包含 页面通过image传参查看passwd文件 页面通过image传参查…

Linux 虚拟网络三大基石:Namespace、Veth pair 与 Bridge

引言 在 Linux 的世界里,虚拟网络技术是系统管理、云计算和容器化不可或缺的一部分。今天,我们将深入探讨构建这些虚拟网络的三大基石:Namespace、Veth 对和 Bridge,揭示它们如何在背后默默支撑起你的网络环境。 Namespace&…

区块链入门

1.1 区块链技术的发展 随着 2008 年比特币(Bitcoin) 的发明,一个被称为区块链(Blockchain) 的新概念进入了人们的视野,这项新技术据信有可能彻底改变整个社会。 区块链有望对每个行业产生颠覆的影响,包括但不限于 IT、金融、政府、媒体、医疗、法律和艺术等。一个流派将区…

速盾:防御ddos攻击的几大有效方法是什么?

DDoS攻击(分布式拒绝服务攻击)是一种恶意攻击手段,旨在通过向目标服务器发送大量的请求,使其无法正常响应正常用户的请求。这种攻击会耗尽服务器的带宽和资源,导致服务不可用。为了保护网络安全,防御DDoS攻…

线性代数 -- 矩阵求导

Tips:本文为理解神经网络的前置知识,整体内容并不全,相关内容还需后续进一步完善。 一、基础 1、标量、向量和矩阵 标量:只有大小,没有方向的量 向量(欧几里得向量):具有大小和方向…

Redis Desktop Manager 0.8.8.384 安装与使用详解

💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「storm…

深入解析多商户商城系统源码:如何开发直播商城小程序?

本篇文章,小编将深入解析多商户商城系统源码的关键技术,并详细探讨如何基于这些源码开发一个功能完善的直播商城小程序。 一、多商户商城系统源码的核心构架 多商户商城系统源码的核心在于其能够支持多个商户独立运营,但同时又在一个统一的平…

LoRA大模型微调的利器

LoRA模型是小型的Stable Diffusion模型,它们对checkpoint模型进行微小的调整。它们的体积通常是检查点模型的10到100分之一。因为体积小,效果好,所以lora模型的使用程度比较高。 这是一篇面向从未使用过LoRA模型的初学者的教程。你将了解LoR…

Linux/Ubuntu服务器 screen 安装与使用

一、screen简单介绍 在Linux系统中,screen是一个非常强大的终端仿真器,它允许用户在一个终端窗口中创建多个子窗口,每个子窗口都可以运行一个独立的会话。screen的主要特点包括: 会话分离:screen允许用户在终端会话中运…

linux安装oracle的详细教程

在Linux系统上安装Oracle数据库涉及多个步骤,从准备工作到安装和初步配置。下面是一个详细的安装教程,以Oracle Database 19c和Oracle Linux(或类似的Red Hat/CentOS)系统为例。 前提条件 确保系统满足Oracle数据库的硬件和软件要…

学习日志8.30--防火墙NAT

目录 一、实验环境配置 二、配置防火墙静态NAT一对一 三、配置防火墙静态NAT多对多 四、配置防火墙NAT端口转换NAPT 五、防火墙smart-nat、easyip 六、防火墙三元组NAT 在学习过基于路由器的NAT网络地址转换,现在学习基于防火墙NAT的网络地址转换,…

电脑里的文件删除了还能恢复吗?这些方法能帮你找回

在数字化时代,电脑已经成为我们日常生活和工作中不可或缺的工具。然而,随着我们在电脑上创建、编辑和保存的文件越来越多,误删文件的情况也时有发生。一旦发现自己不小心删除了重要文件,很多人都会惊慌失措,疑惑这些被…

深入理解Java 8中的Stream API及其应用

深入理解Java 8中的Stream API及其应用 随着Java 8的推出,Java语言引入了许多令人兴奋的新特性,其中最为引人注目的便是Stream API。Stream API 为我们提供了一种全新的集合操作方式,使得数据处理、转换和过滤变得更加简洁、高效。在本文中&…

收藏夹里的“小网站”被误报违规不让上怎么办?如何将Chrome和Edge安装到 D 盘(含用户数据),重装系统也不会丢失收藏夹和密码?

当你用国产浏览器访问网站的时候,有时候会显示这个: 如果确实是违规网站,不让访问也没什么,但是很多都是误报啊,你这样直接来个大红横幅,还让人活不? 那遇到这种误报应当怎么办呢?有…

新电脑Win11系统想要降级为Win10怎么操作?

前言 现在的电脑大部分都是Windows 11系统,组装机还好一些,如果想要使用Windows 10,只需要在安装系统的时候选择Windows 10镜像即可。 但是对于新笔记本、厂商的成品机、一体机来说,只要是全新的电脑,基本上都是Wind…