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

在实际编程中,存在着这样的“数据集”,它们的数值在程序中是稳定的并且个数是有限的。例如春、夏、秋、冬四个数据元素组成了四季的“数据集”,一月到十二月组成了十二个月份的“数据集”,周一到周五及周六周日组成了每周七天的“数据集”。在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的键-值打印出来。

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

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

相关文章

无论是自学还是培训,找工作都要有舍我其谁的信心

不要说自己不行&#xff0c;要说自己可以&#xff0c;做的很不错。 我在投简历的时候&#xff0c;没有包装&#xff0c;然后在与hr沟通的时候&#xff0c;就会遇到 hr问技术能力如何这样的相关问题&#xff0c;其实我觉得我自己不够自信&#xff0c;想要获得一个offer。必须先…

25 OpenCV模板匹配算法

文章目录 介绍匹配算法介绍matchTemplate 模板匹配算子minMaxLoc 找出图像中的最大值最小值代码示例 介绍 模板匹配就是在整个图像区域发现与给定子图像匹配的小块区域。 所以模板匹配首先需要一个模板图像T&#xff08;给定的子图像&#xff09; 另外需要一个待检测的图像-源图…

必看!想入行嵌入式该准备些什么?

近日&#xff0c;很多人问华妹&#xff1a;想入行嵌入式该怎么准备。很能理解大家对于嵌入式的关注&#xff0c;嵌入式系统是当今科技领域中的重要组成部分&#xff0c;它存在于我们生活的方方面面&#xff0c;各行各业。智能化时代的到来也让嵌入式技术炙手可热&#xff01; …

高通平台初步

网上找的图&#xff0c;大体差不多&#xff0c;但是有些细节有点奇怪。 上面的图有点小怪&#xff0c;主要是Libraies&#xff0c;Framework&#xff0c;App&#xff0c;这部分感觉应该是Google的。其他的没啥问题。 大概整理一下编译流程吧。 首先是安装环境&#xff0c;一些…

如何对静态IP进行测试?静态IP有什么优点?

随着互联网的普及&#xff0c;越来越多的人开始使用动态IP进行上网。但是在某些情况下&#xff0c;我们可能需要使用静态IP进行测试或特定的网络设置。本文将介绍如何获取静态IP进行测试以及静态IP的优点。 一、如何获取静态IP进行测试&#xff1f; 1.联系ISP&#xff08;Int…

Controller中接收数组参数

1、场景 需要根据用户id集合批量删除用户数据&#xff0c;前端使用post请求&#xff0c;controller中参数接收数组参数并根据用户id删除用户基本信息 2、分析处理&#xff1a; 2.1、前端请求类型contentType:application/json 请求体中为json字符串&#xff0c;后端新建一个U…

力扣23. 合并 K 个升序链表(最小堆)

Problem: 23. 合并 K 个升序链表 文章目录 题目描述思路及解法复杂度Code 题目描述 思路及解法 1.创建虚拟头节点dummy并创建辅助指针p指向dummy&#xff1b; 2.创建最小堆minHeap将每个链表的头节点存入; 3.当minHeap不为空时每次让p指向从最小堆堆顶取出的节点node&#xff0…

【小沐学AI】Google AI大模型的一点点学习(Python)

文章目录 1、Google AI简介1.1 Google AI Studio1.2 Bard1.3 PaLM1.4 Gemini1.5 Gemini API1.6 Vertex AI1.7 Gemma 2、Google AI开发2.1 快速入门2.1.1 配置开发环境2.1.2 列出所有模型2.1.3 从文本输入生成文本2.1.4 从图像和文本输入生成文本2.1.5 聊天对话 结语 1、Google …

Covalent Network(CQT)与 Celo 集成,推动 Web3 下一代现实资产解决方案的发展

Covalent Network&#xff08;CQT&#xff09;是一个统一的区块链 API 提供商&#xff0c;其已正式与 Celo 集成&#xff0c;Celo 是一个以移动优先的 EVM 兼容链。这一重要的里程碑旨在提升 Celo 生态系统中开发者的能力&#xff0c;通过授予他们访问关键链上数据的权限&#…

踏“时间”与“空间”前来探寻复杂度的奥妙(Java篇)

本篇会加入个人的所谓‘鱼式疯言’ ❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言 而是理解过并总结出来通俗易懂的大白话, 小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的. &#x1f92d;&#x1f92d;&#x1f92d;可能说的不是那么严谨.但小编初心是能让更多人…

基于WTR096-28SS芯片方案的宠物喂食器实现智能化喂食功能

一、简介 本方案宠物喂食器采用了WTR096-28SS芯片方案来实现智能化的喂食功能。该方案结合了先进的技术和设计理念&#xff0c;提供了便捷、智能和个性化的宠物喂食解决方案。 该宠物喂食器具备定时、定量喂食功能&#xff0c;可以根据主人设定的时间和食物量&#xff0c;自动…

xercesc库保存XML功能实现

目录 一 参考链接 二 运行结果 三 代码 一 参考链接 DOM Programming Guide (apache.org) Xerces-c DOM XML文件的构造_xerces-c domimplementation-CSDN博客 Xerces-c库的使用-CSDN博客 二 运行结果 三 代码 #if 1//参考链接&#xff1a; https://blog.csdn.net/RGBMa…

HarmonyOS NEXT应用开发之SideBarContainer侧边栏淡入淡出动效实现案例

介绍 在2in1或平板上&#xff0c;群聊侧边栏是一种较为常用的功能&#xff0c;虽然HarmonyOS已经具备了基本的动效&#xff0c;但是部分情况下开发者可能有定制侧边栏动效的需求&#xff0c;本例主要介绍了如何基于显式动画实现侧边栏的淡入淡出动效。 效果图预览 使用说明&a…

【区间、栈】算法例题

目录 六、区间 48. 汇总区间 ① 49. 合并区间 ② 50. 插入区间 ② 51. 用最少数量的箭引爆气球 ② 七、栈 52. 有效的括号 ① 53. 简化路径 ② 54. 最小栈 ② 55. 逆波兰表达式求值 ② √- 56. 基本计算器 ③ 六、区间 48. 汇总区间 ① 给定一个 无重复元素 的 …

静态代理IP如何测试?

随着互联网的普及&#xff0c;越来越多的人开始使用动态IP进行上网。但是在某些情况下&#xff0c;我们可能需要使用静态IP进行测试或特定的网络设置。本文将介绍如何获取静态IP进行测试以及静态IP的优点。 一、如何获取静态IP进行测试&#xff1f; 1.联系ISP&#xff08;Int…

DM-达梦数据库实时主备搭建

dm实时主备说明 将主库产生的 Redo日志传输到备库&#xff0c;备库接收并重演Redo日志&#xff0c;从而实现备库与主库的数据同步。 一、环境准备 1.1、配置环境准备 首先搭建实时主备&#xff0c;要规划好机器的&#xff0c;我准备两台机器服务器 主服务器 mast…

7-5 表格输出

题目链接&#xff1a;7-5 表格输出 一. 题目 1. 题目 2. 输入输出格式 3. 限制 二、代码 实现一 1. 代码实现 #include <stdio.h>int main(void){printf("------------------------------------\n\ Province Area(km2) Pop.(10K)\n\ ------------------…

14|CAMEL:通过角色扮演脑暴一个鲜花营销方案

能否让 ChatGPT 自己生成这些引导文本呢&#xff1f; CAMEL 交流式代理框架 CAMEL 框架旨在通过角色扮演来促进交流代理之间的自主合作&#xff0c;并为其“认知”过程提供洞察。这种方法涉及使用启示式提示来指导聊天代理完成任务&#xff0c;同时保持与人类意图的一致性。…

【virtio-networking 和 vhost-net 简介】

文章目录 Virtio 基本构建块Virtio spec 和 vhost 协议Vhost-net/virtio-net architectureVirtio-networking and OVS总结参考链接 Virtio 是作为虚拟机 (VM)访问简化device&#xff08;如块设备和网络适配器&#xff09;的 标准化开放接口而开发的。Virtio-net是一种虚拟以太…

大众EA111发动机

大众EA111发动机_什么是大众EA111发动机_太平洋汽车百科 大众EA111发动机_什么是大众EA111发动机_太平洋汽车百科 大众的EA111系列发动机是大众公司小排量发动机的主力&#xff0c;有1.2L、1.4L、1.6L三种排量。大众的EA111系列发动机融合了缸内直喷、涡轮增压等先进技术&…