读书笔记-《ON JAVA 中文版》-摘要25[第二十二章 枚举]

news2024/12/27 18:33:07

文章目录

  • 第二十二章 枚举
    • 1. 基本功能
      • 1.1 基本 enum 特性
    • 2. 方法添加
      • 2.1 方法添加
      • 2.2 覆盖 enum 的方法
    • 3 switch 语句中的 enum
    • 4. values 方法的神秘之处
    • 5. 实现而非继承
    • 6. 随机选择
    • 7. 使用接口组织枚举
    • 8. 使用 EnumSet 替代 Flags
    • 9. 使用 EnumMap
    • 10. 常量特定方法
    • 11. 本章小结

第二十二章 枚举

关键字 enum 可以将一组具名的值的有限集合创建为一种新的类型,而这些具名的值可以作为常规的程序组件使用。这是一种非常有用的功能

1. 基本功能

1.1 基本 enum 特性

package enums;

enum Shrubbery {GROUND, CRAWLING, HANGING}

public class EnumClass {
    public static void main(String[] args) {
        for (Shrubbery s : Shrubbery.values()) { // 实例 .values() 方法返回 enum 实例的数组
            System.out.println(s + " ordinal: " +
                    s.ordinal()); // ordinal() 方法返回 enum 实例在声明时的次序,从 0 开始

            System.out.print(
                    s.compareTo(Shrubbery.CRAWLING) + " ");
            System.out.print(
                    s.equals(Shrubbery.CRAWLING) + " ");
            System.out.println(s == Shrubbery.CRAWLING);

            System.out.println(s.getDeclaringClass()); // 其所属的 enum 类
            System.out.println(s.name()); // 获取值
            System.out.println("********************");
        }

        for (String s :
                "HANGING CRAWLING GROUND AA".split(" ")) {
            // valueOf() 是在 Enum 中定义的 static 方法,
            // 它根据给定的名字返回相应的 enum 实例,
            // 如果不存在给定名字的实例,将会抛出异常
            Shrubbery shrub = Enum.valueOf(Shrubbery.class, s);
            System.out.println(shrub);
        }
    }
}

输出:

GROUND ordinal: 0
-1 false false
class enums.Shrubbery
GROUND
********************
CRAWLING ordinal: 1
0 true true
class enums.Shrubbery
CRAWLING
********************
HANGING ordinal: 2
1 false false
class enums.Shrubbery
HANGING
********************
HANGING
CRAWLING
GROUND
Exception in thread "main" java.lang.IllegalArgumentException: No enum constant enums.Shrubbery.AA
	at java.lang.Enum.valueOf(Enum.java:238)
	at enums.EnumClass.main(EnumClass.java:32)

2. 方法添加

2.1 方法添加

除了不能继承自一个 enum 之外,基本上可以将 enum 看作一个常规的类。也就是说可以向 enum 中添加方法。enum 甚至可以有 main() 方法。

一般来说,我们希望每个枚举实例能够返回对自身的描述,而不仅仅只是默认的 toString() 实现,这只能返回枚举实例的名字。为此,你可以提供一个构造器,专门负责处理这个额外的信息,然后添加一个方法,返回这个描述信息。

package enums;

public enum OzWitch {
    WEST("Miss Gulch, aka the Wicked Witch of the West"),
    NORTH("Glinda, the Good Witch of the North"),
    EAST("Wicked Witch of the East, wearer of the Ruby " +
            "Slippers, crushed by Dorothy's house"),
    SOUTH("Good by inference, but missing");

    private String description;

    OzWitch(String description) {
        this.description = description;
    }

    public String getDescription() {
        return description;
    }

    public static void main(String[] args) {
        for (OzWitch witch : OzWitch.values()) {
            System.out.println(witch + witch.getDescription());
        }
    }
}

输出:

WESTMiss Gulch, aka the Wicked Witch of the West
NORTHGlinda, the Good Witch of the North
EASTWicked Witch of the East, wearer of the Ruby Slippers, crushed by Dorothy's house
SOUTHGood by inference, but missing

2.2 覆盖 enum 的方法

package enums;

import java.util.stream.Stream;

public enum SpaceShip {
    SCOUT, CARGO, TRANSPORT,
    CRUISER, BATTLESHIP, MOTHERSHIP;

    @Override
    public String toString() {
        String id = name();
        String lower = id.substring(1).toLowerCase();
        return id.charAt(0) + lower;
    }

    public static void main(String[] args) {
        Stream.of(values()).forEach(System.out::println);
    }
}

输出:

Scout
Cargo
Transport
Cruiser
Battleship
Mothership

3 switch 语句中的 enum

在 switch 中使用 enum,是 enum 提供的一项非常便利的功能。一般来说,在 switch 中只能使用整数值,而枚举实例天生就具备整数值的次序,并且可以通过 ordinal() 方法取得其次序(显然编译器帮我们做了类似的工作)。

package enums;

enum Signal {GREEN, YELLOW, RED,}

public class TrafficLight {
    Signal color = Signal.RED;

    public void change() {
        switch (color) {
            case RED:
                color = Signal.GREEN;
                break;
            case GREEN:
                color = Signal.YELLOW;
                break;
            case YELLOW:
                color = Signal.RED;
                break;
        }
    }

    @Override
    public String toString() {
        return "The traffic light is " + color;
    }

    public static void main(String[] args) {
        TrafficLight t = new TrafficLight();
        for (int i = 0; i < 5; i++) {
            System.out.println(t);
            t.change();
        }
    }
}

输出:

The traffic light is RED
The traffic light is GREEN
The traffic light is YELLOW
The traffic light is RED
The traffic light is GREEN

4. values 方法的神秘之处

前面已经提到,编译器为你创建的 enum 类都继承自 Enum 类。然而,如果你研究一下 Enum 类就会发现,它并没有 values() 方法。答案是,values() 是由编译器添加的 static 方法。

5. 实现而非继承

所有的 enum 都继承自 Java.lang.Enum 类。由于 Java 不支持多重继承,所以你的 enum 不能再继承其他类:

enum NotPossible extends Pet { ... // Won't work

然而,在我们创建一个新的 enum 时,可以同时实现一个或多个接口。

6. 随机选择

package onjava;

import java.util.Random;

public class Enums {
    private static Random rand = new Random(47);

    public static <T extends Enum<T>> T random(Class<T> ec) {
        return random(ec.getEnumConstants());
    }

    public static <T> T random(T[] values) {
        return values[rand.nextInt(values.length)];
    }
}
package enums;

import onjava.Enums;

enum Activity {
    SITTING, LYING, STANDING, HOPPING,
    RUNNING, DODGING, JUMPING, FALLING, FLYING
}

public class RandomTest {
    public static void main(String[] args) {
        for (int i = 0; i < 20; i++) {
            Activity random = Enums.random(Activity.class);
            System.out.print(random + " ");
        }
    }
}

输出:

STANDING FLYING RUNNING STANDING RUNNING STANDING LYING DODGING SITTING RUNNING HOPPING HOPPING HOPPING RUNNING STANDING LYING FALLING RUNNING FLYING LYING 

7. 使用接口组织枚举

在一个接口的内部,创建实现该接口的枚举,以此将元素进行分组,可以达到将枚举元素分类组织的目的。

package enums.menu;

public interface Food {
    enum Appetizer implements Food {
        SALAD, SOUP, SPRING_ROLLS;
    }
    enum MainCourse implements Food {
        LASAGNE, BURRITO, PAD_THAI,
        LENTILS, HUMMOUS, VINDALOO;
    }
    enum Dessert implements Food {
        TIRAMISU, GELATO, BLACK_FOREST_CAKE,
        FRUIT, CREME_CARAMEL;
    }
    enum Coffee implements Food {
        BLACK_COFFEE, DECAF_COFFEE, ESPRESSO,
        LATTE, CAPPUCCINO, TEA, HERB_TEA;
    }
}
package enums.menu;
import static enums.menu.Food.*;

public class TypeOfFood {
    public static void main(String[] args) {
        // 所有东西都是某种类型的 Food
        Food food = Appetizer.SALAD;
        food = MainCourse.LASAGNE;
        food = Dessert.GELATO;
        food = Coffee.CAPPUCCINO;
    }
}

8. 使用 EnumSet 替代 Flags

Java SE5 引入 EnumSet,是为了通过 enum 创建一种替代品,以替代传统的基于 int 的“位标志”。这种标志可以用来表示某种“开/关”信息。

EnumSet 中的元素必须来自一个 enum。

下面的 enum 表示在一座大楼中,警报传感器的安放位置:

package enums;

public enum AlarmPoints {
    STAIR1, STAIR2, LOBBY, OFFICE1, OFFICE2, OFFICE3,
    OFFICE4, BATHROOM, UTILITY, KITCHEN
}

然后,我们用 EnumSet 来跟踪报警器的状态:

package enums;

import java.util.EnumSet;

import static enums.AlarmPoints.*;

public class EnumSets {
    public static void main(String[] args) {
        // 创建一个空的 EnumSet
        EnumSet<AlarmPoints> points = EnumSet.noneOf(AlarmPoints.class);

        // 添加元素
        points.add(BATHROOM);
        System.out.println("add:" + points);

        points.addAll(
                EnumSet.of(STAIR1, STAIR2, KITCHEN)
        );
        System.out.println("addAll:" + points);

        points = EnumSet.allOf(AlarmPoints.class);
        System.out.println("EnumSet.allOf:" + points);

        points.removeAll(
                EnumSet.of(STAIR1, STAIR2, KITCHEN));
        System.out.println("removeAll:" + points);
        points.removeAll(
                EnumSet.range(OFFICE1, OFFICE4));
        System.out.println("removeAll-EnumSet.range:" + points);

        points = points.complementOf(points);
        System.out.println("complementOf:" + points);
    }
}

输出:

add:[BATHROOM]
addAll:[STAIR1, STAIR2, BATHROOM, KITCHEN]
EnumSet.allOf:[STAIR1, STAIR2, LOBBY, OFFICE1, OFFICE2, OFFICE3, OFFICE4, BATHROOM, UTILITY, KITCHEN]
removeAll:[LOBBY, OFFICE1, OFFICE2, OFFICE3, OFFICE4, BATHROOM, UTILITY]
removeAll-EnumSet.range:[LOBBY, BATHROOM, UTILITY]
complementOf:[STAIR1, STAIR2, OFFICE1, OFFICE2, OFFICE3, OFFICE4, KITCHEN]

9. 使用 EnumMap

EnumMap 是一种特殊的 Map,它要求其中的键(key)必须来自一个 enum。

package enums;

import java.util.*;

import static enums.AlarmPoints.*;

interface Command {
    void action();
}

public class EnumMaps {
    public static void main(String[] args) {
        EnumMap<AlarmPoints, Command> em = new EnumMap<>(AlarmPoints.class);
        em.put(KITCHEN,
                () -> System.out.println("Kitchen fire!"));
        em.put(BATHROOM,
                () -> System.out.println("Bathroom alert!"));
        for (Map.Entry<AlarmPoints, Command> e : em.entrySet()) {
            System.out.print(e.getKey() + ": ");
            e.getValue().action();
        }

        try { // If there's no value for a particular key:
            em.get(UTILITY).action();
        } catch(Exception e) {
            System.out.println("Expected: " + e);
        }
    }
}

10. 常量特定方法

Java 的 enum 有一个非常有趣的特性,即它允许程序员为 enum 实例编写方法,从而为每个 enum 实例赋予各自不同的行为。要实现常量相关的方法,你需要为 enum 定义一个或多个 abstract 方法,然后为每个 enum 实例实现该抽象方法。

package enums;

public enum ConstantSpecificMethod {

    DATE_TIME {
        @Override
        void getInfo() {
            System.out.println("DATE_TIME");
        }
    },
    CLASSPATH {
        @Override
        void getInfo() {
            System.out.println("CLASSPATH");
        }
    };

    abstract void getInfo();

    public static void main(String[] args) {
        for (ConstantSpecificMethod v : values()) {
            v.getInfo();
        }
    }
}

调用 getInfo() 方法时,体现出多态的行为。

11. 本章小结

虽然枚举类型本身并不是特别复杂,但还是将本章安排在全书比较靠后的位置,这是因为,程序员可以将 enum 与 Java 语言的其他功能结合使用,例如多态、泛型和反射。
在这里插入图片描述
(图网,侵删)

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

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

相关文章

pcl--第六节 3D特征描述子

特征描述子 Feature Descriptor 是每个特征点独特的身份认证同一空间点在不同视角的特征点具有高度相似的描述子不同特征点的描述子差异性尽量大通常描述子是一个具有固定长度的向量 描述子可以分为以下几种类型&#xff1a;基于不变性的描述子、基于直方图的描述子、二进制描…

上万条童话故事儿童故事ACCESS\EXCEL数据库

虽然已经有《7千多儿童故事网ACCESS\EXCEL数据库》这种记录数的童话故事类数据&#xff0c;但是遇到了好采集的就总想采集下来&#xff0c;后续有时间或有需求可以再做合并等操作。 分类情况统计为&#xff1a; 儿童故事&#xff1a;儿童小故事&#xff08;1895&#xff09;、…

Cobra眼睛蛇-强大的Golang CLI框架,快速上手的脚手架搭建项目工具,详细安装和使用

Cobra眼睛蛇-强大的Golang CLI框架&#xff0c;快速上手的脚手架搭建项目工具&#xff0c;详细安装和使用。 阅读过k8s源码的同学&#xff0c;应该都知道k8s Scheduler、kubeadm、kubelet等核心组件的命令行交互全都是通过spf13写的Cobra库来实现。本文就来介绍下Cobra的相关概…

成都爱尔李晓峰医生解析“秋季干眼症”!该如何远离

秋高气爽?相较于夏天不然湿热难忍&#xff0c;气候逐渐干燥似乎“好过”了些。但干燥不见得都是好事&#xff0c;环境空气的干同时让人体呈现“燥”&#xff0c;如皮肤干燥、喉痒、口干、干咳、便秘等不适&#xff0c;就连眼睛也不能幸免。 由于眼部水分较其他季节蒸发快&…

时序预测 | MATLAB实现NGO-GRU北方苍鹰算法优化门控循环单元时间序列预测

时序预测 | MATLAB实现NGO-GRU北方苍鹰算法优化门控循环单元时间序列预测 目录 时序预测 | MATLAB实现NGO-GRU北方苍鹰算法优化门控循环单元时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 MATLAB实现NGO-GRU北方苍鹰算法优化门控循环单元时间序列预测&#…

STM32F407 串口使用DMA方式通信

DMA的原理&#xff0c;就是利用寄存器方式进行读写&#xff0c;这样的好处就是相对于中断触发&#xff08;往往一个字节字节的就中断一次&#xff09;&#xff0c;CPU中断次数大大降少&#xff0c;提高了效率&#xff0c;但也影响了实时性。总体来说&#xff0c;对于一般的应用…

系统安装(一)CentOS 7 本地安装

CentOS与Ubuntu并称为Linux最著名的两个发行版&#xff0c;但由于笔者主要从事深度学习图像算法工作&#xff0c;Ubuntu作为谷歌和多数依赖库的亲儿子占据着最高生态位。但最近接手的一个项目里&#xff0c;甲方指定需要在CentOS7上运行项目代码&#xff0c;笔者被迫小小cos了一…

VS Code时间轴插件:MarkWhen

文章目录 简介时间格式事件格式 简介 MarkWhen是一款文本转时间轴的工具&#xff0c;非常好用&#xff0c;也十分炫酷。可在VS Code中搜索插件MarkWhen&#xff0c;点击安装&#xff0c;然后新建一个.mw后缀的文件&#xff0c;就可以使用了&#xff0c;下面举一个简单的例子 …

嵌入式笔试面试刷题(day15)

文章目录 前言一、Linux中的主设备号和次设备号1.查看方法2.主设备号和次设备号的作用 二、软件IIC和硬件IIC的区别三、变量的声明和定义区别四、static在C和C中的区别五、串口总线空闲时候的电平状态总结 前言 本篇文章继续讲解嵌入式笔试面试刷题&#xff0c;希望大家坚持跟…

PyTorch深度学习实战(17)——多任务学习

PyTorch深度学习实战&#xff08;17&#xff09;——多任务学习 0. 前言1. 多任务学习1.1 多任务学习基本概念1.2 多任务学习优势 2. 模型与数据集分析2.1 模型分析2.2 数据集介绍 3. 实现年龄估计和性别分类小结系列链接 0. 前言 多任务学习( Multi-Task Learning, MTL )是一…

SpringCloud Alibaba 整合Sentinel的基本使用

文章目录 一、什么是Sentinel二、Sentinel 的主要特性1. 流量控制&#xff1a;2. 熔断降级&#xff1a;3. 实时监控&#xff1a;4. 规则配置&#xff1a;5. 集成方便&#xff1a; 三、Sentinel 分为哪几部分:1. 核心库&#xff08;Java 客户端&#xff09;2. 控制台&#xff08…

Matlab图像处理-区域描述

一旦一幅图像的目标区域被确定&#xff0c;我们往往用一套描述子来表示其特性。选择区域描述子的动机不单纯为了减少在区域中原始数据的数量&#xff0c;而且也应有利于区别带有不同特性的区域。因此&#xff0c;当目标区域有大小、旋转、平移等方面的变化时&#xff0c;针对这…

ThreeJS-3D教学一基础场景创建

Three.js 是一个开源的 JS 3D 图形库&#xff0c;用于创建和展示高性能、交互式的 3D 图形场景。它建立在 WebGL 技术之上&#xff0c;并提供了丰富的功能和工具&#xff0c;使开发者可以轻松地构建令人惊叹的 3D 可视化效果。 Three.js 提供了一套完整的工具和 API&#xff0…

【深度学习】实验13 使用Dropout抑制过拟合

文章目录 使用Dropout抑制过拟合1. 环境准备2. 导入数据集3. 对所有数据的预测3.1 数据集3.2 构建神经网络 3.3 训练模型3.4 分析模型 4. 对未见过数据的预测4.1 划分数据集4.2 构建神经网络4.3 训练模型4.4 分析模型 5. 使用Dropout抑制过拟合5.1 构建神经网络5.2 训练模型5.3…

基于Qt4的拉格朗日插值实现及使用

目录 1 拉格朗日插值算法 2 实现思路 3 子程序编写 1 框架搭建 2 加载节点值 3 加载插值点 4 位置查找 5 二点线性插值 3 子程序使用 1 拉格朗日插值算法 拉格朗日插值是一种常用的散点插值算法,是是以法国十八世纪数学家约瑟夫拉格朗日命名的一种多项式插值方法。是…

python爬虫——爬取豆瓣top250电影数据(适合初学者)

前言&#xff1a; 爬取豆瓣top250其实是初学者用于练习和熟悉爬虫技能知识的简单实战项目&#xff0c;通过这个项目&#xff0c;可以让小白对爬虫有一个初步认识&#xff0c;因此&#xff0c;如果你已经接触过爬虫有些时间了&#xff0c;可以跳过该项目&#xff0c;选择更有挑…

Linux Shell 实现一键部署podman

podman 介绍 使用 Podman 管理容器、Pod 和映像。从本地环境中无缝使用容器和 Kubernetes&#xff0c;Podman 提供与 Docker 非常相似的功能&#xff0c;它不需要在你的系统上运行任何守护进程&#xff0c;并且它也可以在没有 root 权限的情况下运行。 Podman 可以管理和运行…

JavaWeb后端开发登录操作 登录功能 通用模板/SpringBoot整合

登录功能的思路 前端会传入两个参数:用户名和密码 在用户表中查询用户名,并校对相应的密码(涉及查询操作) SQL语句 select * from emp where username jingyong and password 123456; 如果有则成功,没有则登录失败.不可能为多个,因为添加了unique唯一约束,最终只会有一条 …

如何将转换器应用于时序模型

一、说明 在机器学习的广阔环境中&#xff0c;变压器作为建筑奇迹屹立不倒&#xff0c;以其复杂的设计和捕获复杂关系的能力重塑了我们处理和理解大量数据的方式。 自 2017 年创建第一台变压器以来&#xff0c;变压器类型呈爆炸式增长&#xff0c;包括强大的生成 AI 模型&#…

Kubernetes部署dolphindcheduler-3.1.8问题记录

温故知新 ⁉️问题记录❓问题一&#xff1a;Unschedulable 0/3 nodes are available: pod has unbound immediate PersistentVolumeClaims. preemption: 0/3 nodes are available: 3 No preemption victims found for incoming pod..❗解决方式&#xff1a;创建PV供应&#x1f…