Java枚举解析:掌握枚举的绝佳指南!

news2024/10/5 15:23:20

申明:本人于公众号Java筑基期,CSDN先后发当前文章,标明原创,转载二次发文请注明转载公众号,另外请不要再标原创 ,注意违规

枚举

在Java中,枚举(Enumeration)是一种特殊的数据类型,用于定义一组具有固定值的常量。Java的枚举与其他编程语言中的枚举类似,但它们在语法上略有不同。

以下是在Java中使用枚举的一般用法:

  1. 定义枚举类型:在Java中,可以通过使用enum关键字来定义一个枚举类型。例如,定义一个表示星期几的枚举类型:

    package com.java.enumTest;
    ​
    public enum Weekday {
        MONDAY,
        TUESDAY,
        WEDNESDAY,
        THURSDAY,
        FRIDAY,
        SATURDAY,
        SUNDAY
    }
  2. 赋予枚举常量有意义的名称:在上述例子中,我们为每个星期赋予了有意义的名称,使用大写字母命名,这是Java中枚举常量的命名约定。

  3. 使用枚举常量:一旦定义了枚举类型,你可以在程序中使用它们来表示相关的常量。例如:

    package com.java.enumTest;
    ​
    public class Main {
        public static void main(String[] args) {
            Weekday today = Weekday.SUNDAY;
            
            if (today == Weekday.SUNDAY) {
                System.out.println("It's SUNDAY, time to party!");
            } else {
                System.out.println("It's not SUNDAY, just a regular day.");
            }
        }
    }
    1. 在上面的示例中,我们声明了一个Weekday类型的变量today,并将其赋值为Weekday.TUESDAY。然后,我们可以使用if语句检查today的值是否为Weekday.FRIDAY,从而输出不同的消息。

  4. 遍历枚举类型:在Java中,可以使用增强型的for循环来遍历枚举类型的所有常量:

    package com.java.enumTest;
    ​
    public class Main {
        public static void main(String[] args) {
            for (Weekday day : Weekday.values()) {
                System.out.println("day is " + day);
            }
        }
    }
    1. 使用Weekday.values()可以获取Weekday枚举类型的所有常量,并通过增强型for循环遍历输出每个常量的值。

总结:在Java中,枚举是一种特殊的数据类型,用于定义一组具有固定值的常量。通过为每个常量赋予有意义的名称,枚举可以使代码更具可读性和可维护性。

枚举是如何实现的

在Java中,枚举是通过特殊的类来实现的。在Java 5及以后的版本中,引入了枚举类型(Enumeration type)的支持,使得创建和使用枚举变得更加简单和安全。

以下是Java中枚举的实现方式:

  1. 使用enum关键字:在Java中,你可以使用enum关键字来定义一个枚举类型。当你使用enum定义枚举时,实际上你在创建一个类,并且编译器会自动添加一些特性,以确保该类是一个枚举类型。

  2. 预定义枚举常量:在枚举内部,你可以列出枚举常量。每个枚举常量都是该枚举类型的一个实例,并且是这个枚举类的对象。这些枚举常量通常用大写字母表示,并以逗号分隔。

  3. 自动添加构造函数:编译器会自动为枚举常量添加构造函数,以便在定义枚举常量时传递参数。

  4. 自动添加方法:编译器会自动添加一些有用的方法,例如values()方法用于返回枚举常量数组,valueOf()方法用于将字符串转换为对应的枚举常量。

我们对上面的枚举进行改造,加入常量在里面

package com.java.enumTest;
​
enum Weekday {
    MONDAY("Start of the workweek"),
    TUESDAY("Second workday"),
    WEDNESDAY("Midweek"),
    THURSDAY("Almost there"),
    FRIDAY("End of the workweek"),
    SATURDAY("Weekend"),
    SUNDAY("Weekend");
​
    private final String description;
​
    Weekday(String description) {
        this.description = description;
    }
​
    public String getDescription() {
        return description;
    }
}

运行结果:

我们定义了一个枚举类型Weekday,它有七个枚举常量,每个常量都有一个相关的描述。编译器会自动生成构造函数和values()方法,使得我们可以轻松地遍历所有枚举常量并获取它们的描述。

Java枚举如何⽐较

在Java中,枚举的比较可以使用普通的比较运算符(例如==equals()方法)进行。由于枚举常量是单例的,因此可以使用这些方法来比较枚举常量的值或引用。

我们依旧先创建一个枚举类Color

enum Color {
    RED, GREEN, BLUE
}

然后我们使用 Color 类来做比较

  1. 使用==运算符:在Java中,==运算符用于比较两个对象的引用是否相等,对于枚举常量来说也是如此。如果两个枚举常量是同一个对象的引用,它们将被认为是相等的。在上面的例子中,color1color2都是Color.RED枚举常量的引用,因此它们相等。然而,color1color3是不同枚举常量的引用,因此它们不相等。

    public class ColorMain {
        public static void main(String[] args) {
            Color color1 = Color.RED;
            Color color2 = Color.RED;
            Color color3 = Color.GREEN;
    ​
            System.out.println(color1 == color2); // true
            System.out.println(color1 == color3); // false
        }
    }
  2. 使用equals()方法:枚举类默认继承自java.lang.Enum,而java.lang.Enum类已经实现了equals()方法,用于比较枚举常量。与==运算符不同,equals()方法将比较枚举常量的值是否相等。

    public class ColorMain {
        public static void main(String[] args) {
            Color color1 = Color.RED;
            Color color2 = Color.RED;
            Color color3 = Color.GREEN;
    ​
            System.out.println(color1.equals(color2)); // true
            System.out.println(color1.equals(color3)); // false
        }
    }

在上述示例中,color1color2都是Color.RED枚举常量的引用,因此它们的值相等,equals()方法返回true。然而,color1color3是不同枚举常量,它们的值不相等,equals()方法返回false

还没运行,编译器就已经在告诉我,这样写的结果注定是true,System.out.println里还不如直接写true。

总结:在Java中,枚举的比较可以使用==运算符来比较枚举常量的引用是否相等,以及使用equals()方法来比较枚举常量的值是否相等。对于枚举常量来说,比较通常应该使用equals()方法,以便进行值的比较。

switch怎么用枚举

在Java中,switch语句对枚举的支持是非常好的。Java从JDK 7开始,对switch语句进行了改进,使其可以支持枚举类型作为switch表达式的一种选项。

在使用switch语句处理枚举类型时,可以直接在switch表达式中使用枚举常量,而无需在每个case中使用枚举类型的名称。这使得代码更简洁、更易读。

老样子,创建enum:

enum DayOfWeek {
    MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}

编写switch语句:

public static void main(String[] args) {
    DayOfWeek today = DayOfWeek.WEDNESDAY;

    switch (today) {
        case MONDAY:
            System.out.println("It's Monday.");
            break;
        case TUESDAY:
            System.out.println("It's Tuesday.");
            break;
        case WEDNESDAY:
            System.out.println("It's Wednesday.");
            break;
        case THURSDAY:
            System.out.println("It's Thursday.");
            break;
        case FRIDAY:
            System.out.println("It's Friday.");
            break;
        case SATURDAY:
            System.out.println("It's Saturday.");
            break;
        case SUNDAY:
            System.out.println("It's Sunday.");
            break;
        default:
            System.out.println("Invalid day.");
    }
}

我们把鼠标移到case上,你会发现

MONDAY显示来源于com.java.enumTest.switchTest.DayOfWeek

我们原本要使用MONDAY,只能通过 DayOfWeek.MONDAY,但是在switch里它却可以自己识别。

其实在switch语句中,我们直接使用了枚举常量(如MONDAYTUESDAY等),而无需再使用DayOfWeek.MONDAYDayOfWeek.TUESDAY等。这是Java对枚举类型的改进,使得switch语句更加简洁和易用

枚举与单例

为什么说枚举是实现单例最好的⽅式?

圈重点了,重视线程安全的可能会问。

接下来,我们用枚举来实现单例,先创建一个枚举:

enum Singleton {
    INSTANCE;

    public void output() {
        System.out.println("调用的单例方法");
    }
}

为什么要这么写呢?因为枚举在类加载的时候会被初始化,哪怕是多线程的环境下,它的实例只会被加载一次,因此对于枚举的操作,是线程安全的。

而且Java语言规范中明确指定了枚举的初始化是线程安全的,这意味着多个线程在访问枚举类的时候不会出现竞争条件。枚举还不能被反射机制创建,防止住了反射攻击,而且枚举默认实现了Serializable,因此在序列化和反序列化过程中保证了一致性。因此,无论多少线程并发访问枚举常量,都不会破坏单例模式的唯一性和线程安全性。

简单的输出一下:

public static void main(String[] args) {
    Singleton instance1 = Singleton.INSTANCE;
    Singleton instance2 = Singleton.INSTANCE;

    // 输出为 "true"
    System.out.println(instance1 == instance2);

    instance1.output(); // 输出: "调用的单例方法"
}

我们接下来把它改成多线程情况看看效果:

enum Singleton {
    INSTANCE;

    // 添加一些逻辑
    private int value;

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }
}

我们给枚举新增了属性,并且支持setget ,现在我们进行多线程测试:

public static void main(String[] args) {
    // 线程1创建并使用单例
    Thread thread1 = new Thread(() -> {
        Singleton instance = Singleton.INSTANCE;
        instance.setValue(42);
        System.out.println(Thread.currentThread().getName() + ": " + instance.getValue());
    });

    // 线程2创建并使用单例
    Thread thread2 = new Thread(() -> {
        Singleton instance = Singleton.INSTANCE;
        instance.setValue(99);
        System.out.println(Thread.currentThread().getName() + ": " + instance.getValue());
    });

    thread1.start();
    thread2.start();
}

输出:

这个输出说明了在多线程环境下,两个线程都共享同一个Singleton.INSTANCE实例,并且它们的输出值是相同的。

总结一下枚举之所以被认为是实现单例模式的最好方式,主要有以下几个原因:

  1. 线程安全:枚举在Java中是线程安全的。在多线程环境下,枚举的实例只会被加载一次,并且是在类加载阶段进行初始化,保证了线程安全。

  2. 防止反射攻击:枚举在Java中具有天然的反射安全性。即使使用反射机制尝试创建新的枚举实例,也会导致IllegalArgumentException异常,从而防止了反射攻击。

  3. 防止序列化问题:枚举默认实现了java.io.Serializable接口,因此在序列化和反序列化过程中保证了单例的一致性。

  4. 简洁性和可读性:使用枚举来实现单例模式更加简洁,无需编写复杂的单例模式的代码,也无需考虑线程安全等问题。同时,枚举常量的名称本身就是单例的实例,使代码更加易读和易懂。

枚举的序列化是如何实现的

在Java中,枚举的序列化是由Java编译器和Java运行时库自动处理的。Java的枚举默认实现了java.io.Serializable接口,这意味着枚举类型的实例可以被序列化和反序列化。

当你将一个枚举类型的实例写入到输出流中(例如文件、网络等),或从输入流中读取枚举实例时,Java运行时库会负责将枚举实例转换为其序列化的表示形式,并在反序列化时将其还原为原始的枚举常量。

package com.java.Serializable;
import java.io.*;

enum Color {
    RED, GREEN, BLUE
}

public class Main {
    public static void main(String[] args) {
        // 序列化枚举实例到文件
        try (ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("color.ser"))) {
            Color color = Color.GREEN;
            outputStream.writeObject(color);
            System.out.println("Serialized: " + color);
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 反序列化枚举实例
        try (ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("color.ser"))) {
            Color color = (Color) inputStream.readObject();
            System.out.println("Deserialized: " + color);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

输出:

从代码可知,我们将枚举常量Color.GREEN序列化到文件color.ser中,然后再从文件中反序列化得到一个新的枚举实例。通过序列化和反序列化过程,枚举常量的值得到了正确的保持。

总结:枚举的序列化是由Java运行时库自动处理的。枚举默认实现了java.io.Serializable接口,这使得枚举类型的实例可以轻松地进行序列化和反序列化。在进行序列化时,枚举实例被转换为其序列化的表示形式,反序列化时将其还原为原始的枚举常量。这使得枚举在分布式系统中的传输和存储变得更加方便。

总结

我们讨论了枚举的不同方面,以下是枚举的主要知识点总结:

  1. 枚举是一种特殊的类:在Java中,枚举是一种特殊的类,使用enum关键字定义。它允许你创建一组固定的常量,这些常量在整个程序中保持不变。

  2. 枚举常量:在枚举内部,你可以列出枚举常量。每个枚举常量是该枚举类型的一个实例,并且是这个枚举类的对象。

  3. 枚举的属性和方法:你可以在枚举中定义属性和方法,使枚举常量更具有表现力和功能性。

  4. 枚举的用途:枚举常用于表示一组相关的常量,例如表示一周中的每一天、颜色、状态等。

  5. 枚举的比较:在Java中,枚举的比较可以使用==运算符来比较枚举常量的引用是否相等,也可以使用equals()方法来比较枚举常量的值是否相等。

  6. 枚举和switch语句:Java的switch语句对枚举有很好的支持,你可以直接在switch表达式中使用枚举常量,使得代码更加简洁易读。

  7. 枚举实现单例模式:枚举是实现单例模式最好的方式之一,因为它天然保证了线程安全、反射安全和序列化安全,且代码简洁易读。

  8. 枚举的序列化:枚举默认实现了java.io.Serializable接口,这使得枚举类型的实例可以轻松地进行序列化和反序列化。

总的来说,枚举是Java中一种非常有用和强大的特性,它使得常量的定义更加明确、安全,提高了代码的可读性和可维护性。使用枚举可以避免魔法数值,增强代码的可靠性,并在多个地方使用相同的常量。同时,枚举还可以用于实现单例模式、状态模式等设计模式,使得代码更加简洁和可扩展。

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

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

相关文章

MES管理系统解决方案,助力汽配行业打造数字化工厂

汽配企业的生产与供应链体系必须与整车厂协同,才能确保品质和交期的要求。随着竞争的加剧,车企不断追求更精益化的管理,以应对市场挑战,而高端客户对品质、成本、交期也提出了更高的要求。因此,以合理的价格提供最佳质…

Kubernetes架构和工作流程

目录 一、kubernetes简介 1.k8s的由来 2.为什么用 k8s ? 3.k8s主要功能 二、k8s集群架构与组件 1.Master 组件 1.1Kube-apiserver 1.2Kube-controller-manager 1.3Kube-scheduler 2.Node组件 2.1Kubelet 2.2Kube-Proxy 2.3docker 或 rocket 3.配置存储中…

C++中数据的输入输出介绍

C中数据的输入输出介绍 C中数据的输入输出涉及到的文件 <iostream>&#xff1a;这是C标准库中最常用的头文件之一&#xff0c;包含了进行标准输入输出操作的类和对象&#xff0c;如std::cin、std::cout、std::endl等。 <iomanip>&#xff1a;该头文件提供了一些用…

算法与数据结构(五)--树【1】树与二叉树是什么

一.树的定义 树是一个具有层次结构的集合&#xff0c;是由一个有限集和集合上定义的一种层次结构关系构成的。不同于线性表&#xff0c;树并不是线性的&#xff0c;而是有分支的。 树&#xff08;Tree&#xff09;是n&#xff08;n>0&#xff09;个结点的有限集。 若n0&…

改变C++中私有变量成员的值

1、没有引用的情况&#xff1a; #include <iostream> #include <queue> using namespace std; class Person { public:queue<int>que; public:queue<int> getQueue(){return que;}void push(int a){que.push(a);}void pop(){que.pop();} };int main()…

RS232自由转Profinet网关扫码枪连接电脑操作

你是否曾经遇到过这样的问题&#xff1a;如何在不编写复杂代码的情况下&#xff0c;将条形码数据上传到PLC&#xff1f;今天&#xff0c;我们将为你揭示一个简单的解决方案&#xff01; 让我们来看看这个神奇的组合&#xff1a;捷米的JM-RS485/232-PN (rs232转Profient网关)和…

背景图片及精灵图

.picture {width: 48px;height: 48px;background-image: url(../images/精灵图-侧边功能.png); }为一个有宽高的div设置了背景图片&#xff0c;背景图片只作用在div的content区域内&#xff0c;不作用在padding和border上。 知识点&#xff1a; 背景图使用精灵图&#xff08;…

13-5_Qt 5.9 C++开发指南_基于信号量的线程同步_Semaphore

文章目录 1. 信号量的原理2. 双缓冲区数据采集和读取线程类设计3. QThreadDAQ和QThreadShow 的使用4. 源码4.1 可视化UI设计框架4.2 qmythread.h4.3 qmythread.cpp4.4 dialog.h4.5 dialog.cpp 1. 信号量的原理 信号量(Semaphore)是另一种限制对共享资源进行访问的线程同步机制…

2023年8月美团外卖3-18元红包优惠券天天领取活动日历及美团外卖红包领取使用

2023年8月美团外卖3-18元红包天天领取活动日历 根据上图美团外卖红包领取活动时间表以下时间可以天天领取3-18元美团外卖红包优惠券&#xff1a; 1、2023年8月18日 可领取美团外卖18元神券节红包&#xff1b; 2、2023年8月每周六、周日每天可领取12元美团外卖节红包&#xff…

聊聊工程化 Docker 的最新趋势以及最佳实践

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

AI绘画大师,轻松塑造绝美画作!

前言 随着科技的不断进步&#xff0c;人工智能&#xff08;AI&#xff09;正逐渐渗透到各个领域&#xff0c;艺术也不例外。AI绘 画大师&#xff0c;即 AI 绘画 API&#xff0c;作为其中的一颗明珠&#xff0c;正在引领着艺术创作的革命&#xff0c;它为创作者和艺术爱好者带来…

docker容器创建私有仓库(第三篇)

目录 六、创建私有仓库 七、Docker资源限制 7.1、CPU使用率 7.2、CPU共享比例 7.3、CPU周期限制 7.4、CPU核心限制 7.5、CPU 配额控制参数的混合案例 7.6、内存限制 7.7、Block IO 的限制 7.8、限制bps 和iops 8、Docker数据持久化 8.1、数据持久化介绍 8.2、Volum…

python制作超炫流星雨表白,python好看的流星雨代码

大家好&#xff0c;本文将围绕python制作超炫流星雨表白展开说明&#xff0c;python好看的流星雨代码是一个很多人都想弄明白的事情&#xff0c;想搞清楚html流星雨代码可复制需要先了解以下几个事情。 本文讲述了Python代码示例&#xff1a;实现流星雨特效&#xff01;具有很好…

使用 GitHub Copilot 进行 Prompt Engineering 的初学者指南(译)

文章目录 什么是 GitHub Copilot ?GitHub Copilot 可以自己编码吗&#xff1f;GitHub Copilot 的底层是如何工作的&#xff1f;什么是 prompt engineering?这是 prompt engineering 的另一个例子 使用 GitHub Copilot 进行 prompt engineering 的最佳实践提供高级上下文&…

KepwareEX配置API REST接口

服务端Kepware设置 API允许连接设置 创建通道 请求地址(POST)&#xff1a; https://<主机名_或_ip>:<端口>/config/v1/project/channels 以下示例使用postman工具访问API创建了一个名为Channel1 的通道&#xff0c;其使用在本地主机运行的服务器中的Simulator …

【LeetCode】剑指 Offer Ⅱ 第2章:数组(8道题) -- Java Version

题库链接&#xff1a;https://leetcode.cn/problem-list/e8X3pBZi/ 题目解决方案剑指 Offer II 006. 排序数组中两个数字之和双指针&#xff08;异向&#xff09; ⭐剑指 Offer II 007. 数组中和为 0 的三个数排序 双指针&#xff08;异向&#xff09; ⭐剑指 Offer II 008. 和…

应用在心率血氧健康监测耳机中的三合一灯珠

随着生活节奏的加快&#xff0c;工作压力的加大&#xff0c;越来越多的人开始注重健身&#xff0c;如此一来&#xff0c;可穿戴健身追踪设备就变得很流行。通过对脉搏血氧测量原理的研究&#xff0c;人们已经发现只要测量出两种波长的透射光在一个完整的脉搏波中光强度的变化量…

面试必考精华版Leetcode328. 奇偶链表

题目&#xff1a; 代码(首刷看解析 day22&#xff09;&#xff1a; class Solution { public:ListNode* oddEvenList(ListNode* head) {if(headnullptr) return nullptr;ListNode* oddhead;ListNode* evenHeadhead->next;;ListNode* evenevenHead;while(even!nullptr&&…

华为OD机试真题 Java 实现【N进制减法】【2023 B卷 200分】,附详细解题思路

目录 专栏导读一、题目描述二、输入描述三、输出描述四、Java算法源码五、效果展示1、输入2、输出3、说明 华为OD机试 2023B卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;A卷B卷&#xff09;》。 …

flask中实现restful-api

flask中实现restful-api 举例&#xff0c;我们可以创建一个用于管理任务&#xff08;Task&#xff09;的API。在这个例子中&#xff0c;我们将有以下API&#xff1a; GET /tasks: 获取所有任务POST /tasks: 创建一个新的任务GET /tasks/<id>: 获取一个任务的详情PUT /t…