百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

面试官:来,讲一下枚举类型在开发时中实际应用场景!

off999 2025-06-15 18:37 38 浏览 0 评论

一.基本介绍

枚举是 JDK 1.5 新增的数据类型,使用枚举我们可以很好的描述一些特定的业务场景,比如一年中的春、夏、秋、冬,还有每周的周一到周天,还有各种颜色,以及可以用它来描述一些状态信息,比如错误码等。

枚举类型不止存在在 Java 语言中,在其它语言中也都能找到它的身影,例如 C# 和 Python 等,但我发现在实际的项目中使用枚举的人很少,所以本文就来聊一聊枚举的相关内容,好让朋友们对枚举有一个大概的印象,这样在编程时起码还能想到有“枚举”这样一个类型。

二.枚举的使用方式

很多人不使用枚举的一个重要的原因是对枚举不够熟悉,那么我们就先从枚举的 7 种使用方法说起。

1.常量

在JDK1.5 之前,我们定义常量都是:public static final… 。现在好了,有了枚举,可以把相关的常量分组到一个枚举类型里,而且枚举提供了比常量更多的方法。

public enum Color {

RED, GREEN, BLANK, YELLOW

}

2.switch

JDK1.6之前的switch语句只支持int,char,enum类型,使用枚举,能让我们的代码可读性更强。

enum Signal {

GREEN, YELLOW, RED

}

public class TrafficLight {

Signal color = Signal.RED;

public void change() {

switch (color) {

case RED:

color = Signal.GREEN;

break;

case YELLOW:

color = Signal.RED;

break;

case GREEN:

color = Signal.YELLOW;

break;

}

}

}

3.向枚举中添加新方法

如果打算自定义自己的方法,那么必须在enum实例序列的最后添加一个分号。

public enum Color {

RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);

// 成员变量

private String name;

private int index;

// 构造方法

private Color(String name, int index) {

this.name = name;

this.index = index;

}

// 普通方法

public static String getName(int index) {

for (Color c : Color.values()) {

if (c.getIndex() == index) {

return c.name;

}

}

return null;

}

// get set 方法

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getIndex() {

return index;

}

public void setIndex(int index) {

this.index = index;

}

}

4.覆盖枚举的方法

下面给出一个toString()方法覆盖的例子。

public enum Color {

RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);

// 成员变量

private String name;

private int index;

// 构造方法

private Color(String name, int index) {

this.name = name;

this.index = index;

}

//覆盖方法

@Override

public String toString() {

return this.index+"_"+this.name;

}

}

5.实现接口

所有的枚举都继承自java.lang.Enum类。由于Java 不支持多继承,所以枚举对象不能再继承其他类。

public interface Behaviour {

void print();

String getInfo(); } public enum Color implements Behaviour{

RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);

// 成员变量

private String name;

private int index;

// 构造方法

private Color(String name, int index) {

this.name = name;

this.index = index;

} //接口方法

@Override

public String getInfo() {

return this.name;

}

//接口方法

@Override

public void print() {

System.out.println(this.index+":"+this.name);

}

}

6.使用接口组织枚举

public interface Food {

enum Coffee implements Food{

BLACK_COFFEE,DECAF_COFFEE,LATTE,CAPPUCCINO

}

enum Dessert implements Food{

FRUIT, CAKE, GELATO

}

}

/**

* 测试继承接口的枚举的使用(by 大师兄 or 大湿胸。)

*/

private static void testImplementsInterface() {

for (Food.DessertEnum dessertEnum : Food.DessertEnum.values()) {

System.out.print(dessertEnum + " ");

}

System.out.println();

//我这地方这么写,是因为我在自己测试的时候,把这个coffee单独到一个文件去实现那个food接口,而不是在那个接口的内部。

for (CoffeeEnum coffee : CoffeeEnum.values()) {

System.out.print(coffee + " ");

}

System.out.println();

//搞个实现接口,来组织枚举,简单讲,就是分类吧。如果大量使用枚举的话,这么干,在写代码的时候,就很方便调用啦。

//还有就是个“多态”的功能吧,

Food food = Food.DessertEnum.CAKE;

System.out.println(food);

food = CoffeeEnum.BLACK_COFFEE;

System.out.println(food);

}

7.关于枚举集合的使用

java.util.EnumSet和java.util.EnumMap是两个枚举集合。EnumSet保证集合中的元素不重复;EnumMap中的 key是enum类型,而value则可以是任意类型。关于这个两个集合的使用就不在这里赘述,可以参考JDK文档。

下面是我自己的测试代码。

public class EnumTest {

public static void main(String[] args) {

List<ColorEnum> list = new ArrayList<ColorEnum>();

list.add(ColorEnum.RED);

list.add(ColorEnum.RED); // 重复元素

list.add(ColorEnum.YELLOW);

list.add(ColorEnum.GREEN);

// 去掉重复数据

EnumSet<ColorEnum> enumSet = EnumSet.copyOf(list);

System.out.println("去重:" + enumSet);

// 获取指定范围的枚举(获取所有的失败状态)

EnumSet<ErrorCodeEnum> errorCodeEnums = EnumSet.range(ErrorCodeEnum.ERROR, ErrorCodeEnum.UNKNOWN_ERROR);

System.out.println("所有失败状态:" + errorCodeEnums);

}

}

enum ColorEnum {

RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLOW("黄色", 4);

private String name;

private int index;

private ColorEnum(String name, int index) {

this.name = name;

this.index = index;

}

}

enum ErrorCodeEnum {

SUCCESS(1000, "success"),

ERROR(2001, "parameter error"),

SYS_ERROR(2002, "system error"),

NAMESPACE_NOT_FOUND(2003, "namespace not found"),

NODE_NOT_EXIST(3002, "node not exist"),

NODE_ALREADY_EXIST(3003, "node already exist"),

UNKNOWN_ERROR(9999, "unknown error");

private int code;

private String msg;

ErrorCodeEnum(int code, String msg) {

this.code = code;

this.msg = msg;

}

public int code() {

return code;

}

public String msg() {

return msg;

}

}

三.为什么使用枚举

1.假如不使用枚举

在枚举没有诞生之前,也就是 JDK 1.5 版本之前,我们通常会使用 int 常量来表示枚举,实现代码如下:

public static final int COLOR_RED = 1;

public static final int COLOR_BLUE = 2;

public static final int COLOR_GREEN = 3;

但是使用 int 类型可能存在两个问题:

第一, int 类型本身并不具备安全性,假如某个程序员在定义 int 时少写了一个 final 关键字,那么就会存在被其他人修改的风险,而反观枚举类,它“天然”就是一个常量类,不存在被修改的风险;

第二,使用 int 类型的语义不够明确,比如我们在控制台打印时如果只输出 1...2...3 这样的数字,我们肯定不知道它代表的是什么含义。

那有人就说了,那就使用常量字符呗,这总不会还不知道语义吧?实现示例代码如下:

public static final String COLOR_RED = "RED";

public static final String COLOR_BLUE = "BLUE";

public static final String COLOR_GREEN = "GREEN";

但是这样同样存在一个问题,有些初级程序员会不按套路出牌,他们可能会直接使用字符串的值进行比较,而不是直接使用枚举的字段,实现示例代码如下:

public class EnumTest {

public static final String COLOR_RED = "RED";

public static final String COLOR_BLUE = "BLUE";

public static final String COLOR_GREEN = "GREEN";

public static void main(String[] args) {

String color = "BLUE";

if ("BLUE".equals(color)) {

System.out.println("蓝色");

}

}

}

这样当我们修改了枚举中的值,那程序就凉凉了。

2.枚举使用场景

枚举的常见使用场景是单例,它的完整实现代码如下:

public class Singleton {

// 枚举类型是线程安全的,并且只会装载一次

private enum SingletonEnum {

INSTANCE;

// 声明单例对象

private final Singleton instance;

// 实例化

SingletonEnum() {

instance = new Singleton();

}

private Singleton getInstance() {

return instance;

}

}

// 获取实例(单例对象)

public static Singleton getInstance() {

return SingletonEnum.INSTANCE.getInstance();

}

private Singleton() {

}

// 类方法

public void sayHi() {

System.out.println("Hi,Java.");

}

}

class SingletonTest {

public static void main(String[] args) {

Singleton singleton = Singleton.getInstance();

singleton.sayHi();

}

}

因为枚举只会在类加载时装载一次,所以它是线程安全的。

3.枚举为什么是线程安全的

这一点要从枚举最终生成的字节码说起,首先我们先来定义一个简单的枚举类:

public enum ColorEnumTest {

RED, GREEN, BLANK, YELLOW;

}

然后我们再将上面的那段代码编译为字节码,具体内容如下:

public final class ColorEnumTest extends java.lang.Enum<ColorEnumTest> {

public static final ColorEnumTest RED;

public static final ColorEnumTest GREEN;

public static final ColorEnumTest BLANK;

public static final ColorEnumTest YELLOW;

public static ColorEnumTest[] values();

public static ColorEnumTest valueOf(java.lang.String);

static {};

}

从上述结果可以看出枚举类最终会被编译为被 final 修饰的普通类,它的所有属性也都会被 static 和 final 关键字修饰,所以枚举类在项目启动时就会被 JVM 加载并初始化,而这个执行过程是线程安全的,所以枚举类也是线程安全的类。

4.枚举的比较

我们在枚举比较时使用 == 就够了,因为枚举类是在程序加载时就创建了(它并不是 new 出来的),并且枚举类不允许在外部直接使用 new 关键字来创建枚举实例,所以我们在使用枚举类时本质上只有一个对象,因此在枚举比较时使用 == 就够了。

并且我们在查看枚举的 equlas() 源码会发现,它的内部其实还是直接调用了 == 方法,源码如下:

public final boolean equals(Object other) {

return this==other;

}

四.总结

本文我们介绍了枚举类的 7 种使用方法:常量、switch、枚举中添加方法、覆盖枚举方法、实现接口、在接口中组织枚举类和使用枚举集合等,然后讲了如果不使用枚举类使用 int 类型和 String 类型存在的一些弊端:语义不够清晰、容易被修改、存在被误用的风险,所以我们在适合的环境下应该尽量使用枚举类。并且我们还讲了枚举类的使用场景——单例,以及枚举类为什么是安全的,最后我们讲了枚举比较的小技巧,希望本文对你有帮助。

相关推荐

阿里云国际站ECS:阿里云ECS如何提高网站的访问速度?

TG:@yunlaoda360引言:速度即体验,速度即业务在当今数字化的世界中,网站的访问速度已成为决定用户体验、用户留存乃至业务转化率的关键因素。页面加载每延迟一秒,都可能导致用户流失和收入损失。对...

高流量大并发Linux TCP性能调优_linux 高并发网络编程

其实主要是手里面的跑openvpn服务器。因为并没有明文禁p2p(哎……想想那么多流量好像不跑点p2p也跑不完),所以造成有的时候如果有比较多人跑BT的话,会造成VPN速度急剧下降。本文所面对的情况为...

性能测试100集(12)性能指标资源使用率

在性能测试中,资源使用率是评估系统硬件效率的关键指标,主要包括以下四类:#性能测试##性能压测策略##软件测试#1.CPU使用率定义:CPU处理任务的时间占比,计算公式为1-空闲时间/总...

Linux 服务器常见的性能调优_linux高性能服务端编程

一、Linux服务器性能调优第一步——先搞懂“看什么”很多人刚接触Linux性能调优时,总想着直接改配置,其实第一步该是“看清楚问题”。就像医生看病要先听诊,调优前得先知道服务器“哪里...

Nginx性能优化实战:手把手教你提升10倍性能!

关注△mikechen△,十余年BAT架构经验倾囊相授!Nginx是大型架构而核心,下面我重点详解Nginx性能@mikechen文章来源:mikechen.cc1.worker_processe...

高并发场景下,Spring Cloud Gateway如何抗住百万QPS?

关注△mikechen△,十余年BAT架构经验倾囊相授!大家好,我是mikechen。高并发场景下网关作为流量的入口非常重要,下面我重点详解SpringCloudGateway如何抗住百万性能@m...

Kubernetes 高并发处理实战(可落地案例 + 源码)

目标场景:对外提供HTTPAPI的微服务在短时间内收到大量请求(例如每秒数千至数万RPS),要求系统可弹性扩容、限流降级、缓存减压、稳定运行并能自动恢复。总体思路(多层防护):边缘层:云LB...

高并发场景下,Nginx如何扛住千万级请求?

Nginx是大型架构的必备中间件,下面我重点详解Nginx如何实现高并发@mikechen文章来源:mikechen.cc事件驱动模型Nginx采用事件驱动模型,这是Nginx高并发性能的基石。传统...

Spring Boot+Vue全栈开发实战,中文版高清PDF资源

SpringBoot+Vue全栈开发实战,中文高清PDF资源,需要的可以私我:)SpringBoot致力于简化开发配置并为企业级开发提供一系列非业务性功能,而Vue则采用数据驱动视图的方式将程序...

Docker-基础操作_docker基础实战教程二

一、镜像1、从仓库获取镜像搜索镜像:dockersearchimage_name搜索结果过滤:是否官方:dockersearch--filter="is-offical=true...

你有空吗?跟我一起搭个服务器好不好?

来人人都是产品经理【起点学院】,BAT实战派产品总监手把手系统带你学产品、学运营。昨天闲的没事的时候,随手翻了翻写过的文章,发现一个很严重的问题。就是大多数时间我都在滔滔不绝的讲理论,却很少有涉及动手...

部署你自己的 SaaS_saas如何部署

部署你自己的VPNOpenVPN——功能齐全的开源VPN解决方案。(DigitalOcean教程)dockovpn.io—无状态OpenVPNdockerized服务器,不需要持久存储。...

Docker Compose_dockercompose安装

DockerCompose概述DockerCompose是一个用来定义和管理多容器应用的工具,通过一个docker-compose.yml文件,用YAML格式描述服务、网络、卷等内容,...

京东T7架构师推出的电子版SpringBoot,从构建小系统到架构大系统

前言:Java的各种开发框架发展了很多年,影响了一代又一代的程序员,现在无论是程序员,还是架构师,使用这些开发框架都面临着两方面的挑战。一方面是要快速开发出系统,这就要求使用的开发框架尽量简单,无论...

Kubernetes (k8s) 入门学习指南_k8s kubeproxy

Kubernetes(k8s)入门学习指南一、什么是Kubernetes?为什么需要它?Kubernetes(k8s)是一个开源的容器编排系统,用于自动化部署、扩展和管理容器化应用程序。它...

取消回复欢迎 发表评论: