Java学习笔记20——枚举类型的创建与使用

news2024/12/23 14:35:08

在实际编程中,存在着这样的“数据集”,它们的数值在程序中是稳定的并且个数是有限的。例如春、夏、秋、冬四个数据元素组成了四季的“数据集”,一月到十二月组成了十二个月份的“数据集”,周一到周五及周六周日组成了每周七天的“数据集”。在Java中可以使用枚举类型来表示这些数据。

在Java5之前,没有枚举类型,需要使用静态常量。如下:

public class Week {
    static final int SUNDAY = 0;
    static final int MONDAY = 1;
    static final int TUESDAY = 2;
    static final int WEDNESDAY = 3;
    static final int THURSDAY = 4;
    static final int FRIDAY = 5;
    static final int SATURDAY = 6;
}

要使用上面这些模拟的枚举值时,直接使用Week类名调用静态常量即可。不过这种方式可能会出现一个问题,当声明一个方法中接受int类型的参数时,也可以使用上面定义的静态常量作为实参传入,编译器不会报错,但是会影响代码的阅读性。

Java5开始新增了枚举类型,避免了上面的问题。定义枚举类型,使用enum关键字,声明格式如下:

[修饰符] enum 枚举名 {
    枚举成员
}

修饰符:public、private、internal。

枚举名:符合Java规范的标识符。

枚举成员:任意枚举成员之间不能有相同的名字,多个枚举成员之间使用逗号隔开,最后一个成员后面可以有分号,也可以没有。

下面代码定义了一个枚举类型Week,用该类型声明的变量只能存储枚举类型定义中给出的某个枚举值,或者null值。

public enum Week {
    Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday;
}

可以使用swith语句很方便地判断枚举的值,如下:

class WeekTest {
    static void UseWeek(Week day) {  // 使用Week枚举类型声明变量day
        switch (day) {
            case Sunday:
                System.out.println("星期天");
                break;
            case Monday:
                System.out.println("星期一");
                break;
            case Tuesday:
                System.out.println("星期二");
                break;
            case Wednesday:
                System.out.println("星期三");
                break;
            case Thursday:
                System.out.println("星期四");
                break;
            case Friday:
                System.out.println("星期五");
                break;
            case Saturday:
                System.out.println("星期六");
                break;
        }
    }

    public static void main(String[] args) {
        WeekTest.UseWeek(Week.Monday);   // 输出“星期一”
    }
}

枚举类型最常用的地方就是在switch语句中使用。上面的代码在UseWeek()方法中定义了一个形参day,其类型是Week枚举类型,将变量day作为swith语句的表达式,通过对day的值来配符case语句中的常量的值,若相等执行相应的case语句。

另外:case表达式中可以直接写入枚举值(写也可以),不用添加枚举类作为限定。

枚举的本质是类,只不过是使用enum关键字替代class,它所创建的类型都是java.lang.Enum类的子类,而java.lang.Enum是一个抽象类。枚举屏蔽了枚举值的类型信息,不像在用public static final 三个修饰符修饰的常量时必须指定类型。枚举是用来构建常量数据结构的模板,而且这个模板也可以扩展(添加属性、方法、构造函数)。

所以上面使用enum关键字创建的Week枚举,其源文件名是Week.java,编译后的文件名是Week.class,和类一样。

下面代码是使用JDK自带的javap工具来反编译Week.class文件,会输出如下的结果:

//PS D:\MyJavaLearn\> javap Week.class
//Compiled from "Week.java"

public final class com.test.Week extends java.lang.Enum<Week> {
  public static final Week Sunday;
  public static final Week Monday;
  public static final Week Tuesday;
  public static final Week Wednesday;
  public static final Week Thursday;
  public static final Week Friday;
  public static final Week Saturday;
  public static Week[] values();
  public static Week valueOf(java.lang.String);
  static {};

从上面反编译的代码可以看出,枚举类型实际上还是一个类,枚举值还是静态常量,使用public static final 三个修饰符。但是,这些常量的类型就是类本身。

从反编译的代码中还可以看到Week类增加了两个静态方法values()和valueOf()。

在Java语言中,每一个枚举类型成员都可以当做一个Enum类的实例。而且枚举成员会默认被public static final修饰,所以可以直接使用枚举名调用它。

java.lang.Enum类是一个抽象类,所有创建的枚举类型自动实现了它,故所有枚举实例都可以调用枚举类定义的方法。常用的如下:

枚举常用方法
方法名说明
compareTo比较枚举与指定对象的定义顺序
valueOf(Class<T>enumType,String name)返回带指定名称的指定枚举类型的枚举常量
values()以数组的形式返回枚举类型的所有成员
ordinal()返回枚举常量的索引位置(它在枚举声明中的位置,其中初始常量序数为零
toString()返回枚举常量的名称

下面代码定义了一个颜色枚举类型,使用了如上方法的调用。

public class EnumMethod {
    // 定义颜色枚举类
    public enum Color {
        red,yellow,green,blue,pink,brown,purple
    }

    public static void main(String[] args) {
        // ordinal()方法的使用:获取指定枚举实例的索引
        for (int i=0;i<Color.values().length;i++) {
            // 循环输出枚举类中所有枚举常量的索引值
            System.out.print(Color.values()[i] + "的索引:" + Color.values()[i].ordinal() + "  ");
        }

        System.out.println();

        // toString()方法的使用,返回枚举常量的名称
        System.out.println("toString()方法的使用:" + Color.blue.toString());
        // compareTo()方法的使用
        System.out.println("compareTo()方法的使用:" + Color.blue.compareTo(Color.red));
        // valueOf()方法使用
        System.out.println("valueOf方法使用:" + Color.valueOf("green"));
    }
}

输出的结果如下:

 为枚举添加属性和方法

枚举类型出来Java提供的方法,还可以定义自己的方法。但需要注意,这时需要在枚举实例的最后一个成员后面添加分号,并且必须先定义枚举实例。如下代码:

package com.test;

public enum EnumProperty {
    // 枚举成员定义,且必须以分好结尾
    Jan("January"),Feb("February"),Mar("March"),Apr("April"),May("May"),Jun("June"),
    Jul("July"),Aug("August"),Sep("September"),Oct("October"),Nov("November"),Dec("December");

    // 定义枚举类型的private属性
    private final String month;

    // 定义私有构造函数(也可以是public)
    private EnumProperty(String month) {
        this.month = month;
    }

    // 定义枚举类的public方法
    public String getMonth(){
        return month;
    }
}

class EnumPropertyTest {
    public static void main(String[] args) {
        // 使用for循环遍历枚举类型,并输出
        for(EnumProperty en :EnumProperty.values()) {
            System.out.println(en + " : " + en.getMonth());
        }
    }
}

上面代码定义了EnumPropery枚举,声明了它的私有属性month和私有构造方法EnumPropery(),及public方法getMonth()。构造方法EnumPropery()作用是为私有属性month赋值,getMonth()方法是获取私有属性month的值。在上面的测试类中,通过枚举的values()方法获得枚举的所有成员,再通过for循环遍历成员,其中调用自定义的方法getMonth()获取枚举的成员。

请注意:在定义枚举成员时的Jan("January"),其实是调用了构造函数,并传入“January”进行初始化枚举的私有属性month,给其进行赋值“January”。

枚举值的比较

如果只是简单地比较两个枚举类型的值是否相等,那么直接使用比较运算符“==”即可。如果需要进一步地比较,则可以使用枚举值的compareTo方法。

枚举的对象有一个ordinal()方法可以获取枚举值的一个数值表示,compareTo()方法实际是比较两个值的ordinal的值。比如如下代码:

System.out.println(Week.Monday.compareTo(Week.Thursday));

上面代码运行的结果是:-3

使用compareTo()方法比较两个枚举值,当结果小于0时,compareTo左边的枚举值小于右边的枚举值;当结果为0时,则说明两个枚举值相等;当结果大于0时,则说明compareTo左边的枚举值大。

注意:Java中,不允许使用“>”和“<”比较运算符比较两个枚举值。

另外:自定义的比较方法不能取名为compareTo,因为所有枚举类型生产的类都是从Enum类继承的,而Enum类中的compareTo方法不能被覆盖。

EnumSet和EnumMap类

为了更高效地操作枚举类型,java.util中有EnumSet和EnumMap两个类。

1)EnumMap类

EnumMap类是为枚举类型专门量身定做的Map实现。EnumMap类只能接收同一枚举类型的实例作为键值,并且由于枚举类型实例的数量相对固定且有限,所以EnumMap类使用数组来存放与枚举类型相关的值,这使得EnumMap的效率非常高。

2)EnumSet类

EnumSet类是枚举类型的高性能Set实现。EnumSet要求放入它的枚举常量必须属于同一枚举类型,它提供了许多工厂方法以便于初始化。

EnumSet常用方法
方法说明
allOf(Class<E>elementType) 

创建一个包含指定枚举类型的所有枚举成员的EnumSet对象

complementOf(EnumSet<E> s)创建一个与指定枚举类型对象s相同的EnumSet对象,包含指定s中不包含的枚举成员
copyOf(EnumSet<E> s)创建一个与指定枚举类型对象s相同的EnumSet对象,包含与s中相同的枚举成员
noneOf(Class<E>elementType) 创建一个具有指定枚举类型的空EnumSet对象
of(E first,E... rest)创建一个包含指定枚举成员的EnumSet对象
range(E from,E to)创建一个包含从from到to的所有枚举成员的EnumSet对象

package com.test;
import java.util.*;
import java.util.Map.Entry;

enum EnumMonth {
    Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Noe,Dec
}

public class EnumTest {
    public static void main(String[] args) {
        // EnumSet的使用
        EnumSet<EnumMonth> monthSet = EnumSet.allOf(EnumMonth.class);
        for (EnumMonth month : monthSet) {
            System.out.print(month + "  ");
        }
        System.out.println();

        // EnumMap的使用
        EnumMap<EnumMonth,String> monthMap = new EnumMap(EnumMonth.class);
        monthMap.put(EnumMonth.Jan,"一月份");
        monthMap.put(EnumMonth.Feb,"二月份");
        monthMap.put(EnumMonth.Mar,"三月份");
        monthMap.put(EnumMonth.Apr,"四月份");
        monthMap.put(EnumMonth.May,"五月份");
        monthMap.put(EnumMonth.Jun,"六月份");
        // 省略了7-12月份
        for (Iterator<Entry<EnumMonth,String>> ite=monthMap.entrySet().iterator();ite.hasNext();) {
            Entry<EnumMonth,String> entry = ite.next();
            System.out.print(entry.getKey().name() + ":" + entry.getValue() + "  ");
        }
    }
}

运行的结果如下:

上面代码,通过EnumSet的allOf()方法获得枚举类EnumMonth的所有枚举成员,并通过for循环打印输出所有的枚举成员。

对于EnumMap的使用,是通过其构造方法返回一个指定枚举类型的空的枚举映射monthMap,再通过它的put()方法将枚举成员依次添加到这个空枚举映射monthMap变量中。然后通过迭代器Itertor和for循环依次将EnumMap的键-值打印出来。

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

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

相关文章

了解交换机上的SFP和QSFP端口

在当今互联的世界中&#xff0c;可靠、高效的网络通信对于企业的蓬勃发展至关重要。为了实现顺畅的连接&#xff0c;了解能够实现该目标的技术非常重要。其中一项关键技术是交换机上的SFP和QSFP端口。本文将简要介绍这些概念&#xff0c;定义并解释交换机SFP端口和QSFP端口的优…

面试官:对于 Java 中多态的理解是什么?

面试官&#xff1a;对于 Java 中多态的理解是什么&#xff1f; 题目 面试官&#xff1a;对于 Java 中多态的理解是什么&#xff1f; 推荐解析 1.父类的引用指向子类的对象 子类重写父类的方法&#xff1a;子类可以继承父类的方法&#xff0c;并对其进行重写。当通过父类的…

Python炒股自动化(5):通过接口查询订单,查询账户资产

上一节我们演示了报单撤单&#xff0c;也叫提交委托和撤销委托&#xff0c;我习惯说下单撤单&#xff0c;与交易所建立连接这里不演示了&#xff0c;没看的可以点下面链接了解一下 Python炒股自动化&#xff08;4&#xff09;&#xff1a;通过接口向交易所发送订单https://cai…

关于msvcp140.dll丢失的解决方法详情介绍,修复dll文件的安全注意事项

在使用电脑的过程中&#xff0c;是否有遇到过关于msvcp140.dll丢失的问题&#xff0c;遇到这样的问题你是怎么解决的&#xff0c;都有哪些msvcp140.dll丢失的解决方法是能够完美解决msvcp140.dll丢失问题的&#xff0c;今天小编将带大家去了解msvcp140.dll文件以及分析完美解决…

2024年是否值得投资购买Photoshop?优势与劣势解析

相信所有的设计师都是对的 Adobe Photoshop 非常熟悉&#xff0c;它是一款专业的照片编辑软件应用程序。如果您有兴趣购买&#xff0c;请购买。 Adobe Photoshop&#xff0c;也许你想知道Adobe Photoshop价格。Adobe Photoshop的价格反映了它强大的使用价值&#xff0c;下面是不…

Vuex状态、数据持久化(vue2、vue3状态数据持久化)

简介&#xff1a;Vuex是一个仓库&#xff0c;是vue的状态管理工具&#xff0c;存放公共数据&#xff0c;任何组件都可以使用vuex里的公共数据。Vuex提供了插件系统&#xff0c;允许我们使用 vuex-persistedstate插件&#xff0c;将Vuex的状态持久化到本地存储中&#xff0c;解决…

@arco.design radioGroup 组件手写 beforeChange 方法

官方是没有提供 beforeChange 事件的&#xff0c;只能自己写一个 子组件&#xff08;CustomRadioGroup&#xff09; <template><a-radio-group :model-value"modelValue" change"onRadioChange"><a-radio v-for"item in list" …

【C语言】基础(与python语法比较)

1、【C#】 printf ① 头文件stdio.h&#xff0c;② 注意语法格式&#xff0c;③ printf的文本结尾不换行&#xff0c;④ printf中参数是字符&#xff0c;其它类型可以转为文本&#xff0c;例如"%i","%f"等。 #include <stdio.h>int main(void) {in…

今日问题:动态分配内存出错

2024.3.22 在搜素了许多文章和查阅了许多博客后依然没有找到问题所在&#xff0c;最后无意之间翻看以前的关于动态内存管理的代码后发现&#xff1a; 没加头文件&#xff1a;#include<stdlib.h> 苦笑不得了属于是 #define _CRT_SECURE_NO_WARNINGS 1 #include<stdio…

抖音,剪映,TikTok,竖屏短视频转场pr模板视频素材

120个叠加效果视频转场过渡素材&#xff0c;抖音,剪映,TikTok,短视频转场pr模板项目工程文件。 效果&#xff1a;VHS、光效、胶片、霓虹灯闪光、X射线、信号、老电影等。 适用软件&#xff1a;Adobe Premiere Pro 2018 12.0或更高版本。 视频素材与大多数应用程序兼容&#xff…

JavaWeb:AOP、配置优先级、Bean管理、SpringBoot原理、Maven高级

1 AOP 1.1 基本语法 面向切面编程、面向方面编程&#xff0c;面向特定方法编程 在管理bean对象的过程中&#xff0c;主要通过底层的动态代理机制&#xff0c;对特定的方法进行编程 应用&#xff1a;统计每一个业务方法的执行耗时 xml引入依赖 <!-- AOP-->&l…

全闪存存储怎样对AI大模型赋能

随着科技的飞速发展&#xff0c;人工智能&#xff08;AI&#xff09;与机器人学习&#xff08;ML&#xff09;已经逐渐成为引领未来的核心技术。近期火爆市场的Chat GPT AI大模型深度结合AI与机器人学习技术&#xff0c;实现人机交流、学术研究、内容创作等应用&#xff0c;国内…

【进阶五】Python实现SDVRP(需求拆分)常见求解算法——禁忌搜索+模拟退火算法(TS+SA)

基于python语言&#xff0c;采用经典禁忌搜索&#xff08;TS&#xff09;模拟退火&#xff08;SA&#xff09;对 需求拆分车辆路径规划问题&#xff08;SDVRP&#xff09; 进行求解。 目录 往期优质资源1. 适用场景2. 代码调整3. 求解结果3.1 TS3.2 SA 4. 代码片段参考 往期优质…

迷宫(蓝桥杯)——DFS和BFS

迷宫 题目描述 下图给出了一个迷宫的平面图&#xff0c;其中标记为 1 的为障碍&#xff0c;标记为 0 的为可以通行的地方。 010000 000100 001001 110000迷宫的入口为左上角&#xff0c;出口为右下角&#xff0c;在迷宫中&#xff0c;只能从一个位置走到这 个它的上、下、左…

表格列内容过长显示省略号,并悬浮展示信息

自定义全局指令&#xff1a; 指定超出行数的内容&#xff0c;以省略号替代。 // main.ts import App from ./App.vue;const app createApp(App);// 自定义指令app.directive(textOverflow, {mounted(el, binding, vnode) {const maxRows binding.value || 3;// 添加样式vnod…

哪些因素决定SSL证书的定价?DV、OV和EV证书多少钱?

在当前网络环境安全问题日益凸显的时代背景下&#xff0c;SSL证书已成为保障网站及用户数据传输安全的核心手段。然而&#xff0c;由于不同供应商、证书类型和功能差异&#xff0c;SSL证书的价格存在较大浮动空间。本文将概述SSL证书的基本定价范围及其决定因素&#xff0c;为选…

什么快递可以寄摩托车?看你要啥样的了

一辆49cc的二冲程摩托车仅需561元。 购买125的组装车不会超过1元&#xff0c;购买250品牌发动机的组装车不会超过4000元。 购买一辆名牌摩托车大约需要4000到10000元。 花一万到两百万多就能买到一辆像样、动力强劲、能玩的炫酷摩托车。 哈哈&#xff0c;就看你想要什么了&…

基于ssm的乡镇自来水收费系论文

摘 要 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好地为人们提供服务。针对乡镇自来水收费信息管理混乱&#xff0c;出错率高&#xff0c;信息安…

算法第三十一天-直方图的水量

直方图的水量 题目要求 解题思路 使用面向列的计算比面向行的计算更加容易。我们只需要考虑当前的位置的左右最高模板的高度。 方法一、暴力解法 每个位置能接到多少雨水&#xff0c;很容易想到[木桶效应]&#xff0c;即是由两边最短的木板限制的。那么直观思路就是&#x…

PTA-练习5

目录 实验7-2-1 求矩阵各行元素之和 实验7-2-2 矩阵运算 实验7-2-3 求矩阵的局部极大值 实验7-2-5 判断上三角矩阵 实验7-2-6 打印杨辉三角 实验7-2-7 方阵循环右移 实验7-2-8 找鞍点 实验7-2-1 求矩阵各行元素之和 #include<stdio.h> #include<stdlib.h> …