还有你不知道的Java枚举特性(下篇)

你一定需要知道的高阶JAVA枚举特性! JAVA枚举,比你想象中还要有用! 我经常发现自己在Java中使用枚举来表示某个对象的一组潜在值。 在编译时确定类型可以具有什么值的能力是一种强大的能力,它为代码提供了结构和意义。 当我第一次了解枚举时,当时我认为它们只是一个为常量命名的工具,可以很容易地被静态常量字符串ENUM_VAL_NAME所取代。 后来我发现我错了。事实证明,Java枚举具有相当高级的特性,可以使代码干净、不易出错,功能强大。 让我们一起来看看Java中的一些高级枚举特性,以及如何利用这些特性使代码更简单、更可读。 枚举是类! 在J 阅读详情

简介

这篇是博文 还有你不知道的Java枚举特性(上篇) 的下篇,可以点击下面的链接前往。

本篇主要内容:

  • Java 枚举是一个特殊的类,聊聊其方法的重写
  • 如何使用接口来组织 Java 枚举?
  • 如何使用枚举实现 Java 的单例模式
  • JDK 数据结构中关于枚举的集合 EnumSet 和字典 EnumMap

重写枚举的方法

所有的枚举类都继承自 Enum,在这个父类当中 toString、equals 和hashCode 的三个方法,可以看一下,源码如下:

public String toString() {
	return name;
}

public final boolean equals(Object other) { 
	return this==other;
}

public final int hashCode() {
	return super.hashCode();
}

可以看出在这三个方法当中,我们只能重写 toString 方法,另外两个方法都是 final 修饰的方法,不可以被子类重写。

我们在自定义的枚举中,可以重写 toString 方法的,示例如下:

public enum Color {
    RED("red color"),
    GREEN("green color"),
    BLUE("blue color"),
    YELLOW("yellow color");

    Color(String name) {
        _name = name;
    }

    private String _name;
    
    @Override
    public String toString() {
        return "this.name: " + _name;
    }
}

关于 Enum 的源码,可以在博文 Java 枚举的本质 中的文末翻阅。

对于 Java 中所有枚举都是继承自 Enum,大家可以去使用 javap 命令反编译看看,如下代码是 javap 后的简单示例:

public final class com.veryitman.Color extends java.lang.Enum<com.veryitman.Color> {
  public static final com.veryitman.Color RED;
  public static final com.veryitman.Color GREEN;
  public static final com.veryitman.Color BLUE;
  public static final com.veryitman.Color YELLOW;
  public static com.veryitman.Color[] values();
  public static com.veryitman.Color valueOf(java.lang.String);
  static {};
}

可以看到 Color 是继承自 java.lang.Enum 的,Enum 是一个抽象类并实现了 Comparable 和 Serializable 这两个接口,如下:

public abstract class Enum<E extends Enum<E>> implements Comparable<E>, Serializable 

使用接口组织枚举

当我们定义的枚举过多且又有很多嵌套,可以使用接口来组织这些枚举,将其归类,这样一来不仅代码看起来很规范,并且也很好管理代码。

如下示例,使用接口 MobileTool 来组织两个枚举。

public interface MobileTool {
        enum Phone implements MobileTool {
            HUAWEI, iPhone, OPPO, XIAOMI
        }

        enum Pad implements MobileTool {
            iPad, WEPad, sPad
        }
    }

简单的可以这样使用,示例如下:

MobileTool mphone = MobileTool.Phone.HUAWEI;
mphone = MobileTool.Phone.iPhone;

MobileTool mpad = MobileTool.Pad.iPad;
mpad = MobileTool.Pad.sPad;

枚举实现单例模式

在 Effective Java 这本书籍中,作者有个这样下面的描述:

"This approach is functionally equivalent to the public field approach, except that it is more concise, provides the serialization machinery for free, and provides an ironclad guarantee against multiple instantiation, even in the face of sophisticated serialization or reflection attacks. While this approach has yet to be widely adopted, a single-element enum type is the best way to implement a singleton."

核心的意思是

使用枚举实现单例的方法虽然还没有广泛采用,但单元素的枚举类型已经成为实现 Java 单例模式的最佳方法。

我们用枚举实现一下单例模式,示例代码如下:

public enum Foo {
	INSTANCE;

	public void printFoo() {
		System.out.println("Foo here.");
	}
}

相比 Java 中其他的单例实现方式,此时此刻你会发现,枚举实现单例的代码会精简很多。

那么,枚举实现单例模式到底有哪些优势呢?或者换句话说,就这样实现单例靠谱吗?

经过大量例子和 Java 编程专家的讲解,枚举实现单例模式相当靠谱,它具有以下一些特点:

1、枚举实现的单例模式是线程安全的

本质上面来讲,枚举实现的单例之所以是线程安全的,这个跟 Java 的类加载机制有关。从上面反编译的代码来看,枚举是 final class 并且每个枚举值都是 static 的,这里牵扯到 ClassLoader 的相关知识,如果有兴趣建议大家去研究一下。

总之,对于我们任何一个枚举在第一次被真正用到之时,会被 Java 虚拟机加载并且完成初始化,而这个初始化过程是线程安全的,所以你需要记住枚举实现的单例模式是多线程安全的就可以了。

2、枚举可解决反射/反序列化问题

我们知道,一般的单例模式都存在两个问题,一个是可以通过反射调用,另一个就是可以通过序列化和反序列化来破坏单例。

一般解决反射调用可以通过私有构造方法中做处理,示例代码如下:

private static boolean flag = false;

private Foo() {
	synchronized (this) {
		if (false == flag) {
			flag = true;
		} else {
			throw new RuntimeException("不能反复创建");
		}
	}
};

了解序列化原理的同学,可以通过在单例类中实现 readResolve 方法就可以避免反序列化攻击这个问题了。示例代码如下:

private Object readResolve() {
    return INSTANCE;
}

Java 的枚举的反序列化实现并不是通过反射实现的,也就是说枚举的序列化和反序列化是有经过特殊定制和处理的,这就可以避免反序列化过程中由于反射而导致的单例被破坏问题。

总之,枚举实现的单例模式不仅可以防止反射破坏,还可以防止序列化破坏单例。

除枚举实现单这种方式以外,我一般使用下面两种方式来实现单例模式。

饿汉式的单例模式写法

public class Foo {
    private static Foo instance = new Foo();
    
    private Foo () {
        
    }
    
    public static Foo getInstance() {
    	return instance;
    }
}

静态内部类实现单例模式

public class Foo {
    private static class FooHolder {
    	private static final Foo INSTANCE = new Foo();  
    }
    
    private Foo () {
    	
    }
    
    public static final Foo getInstance() {  
    	return FooHolder.INSTANCE;
    }
}  

枚举集合

EnumSet 是一个专为枚举设计的集合类,EnumSet 中的所有元素都必须是指定枚举类型的枚举值。

EnumSet 类结构图如下:

[外链图片转存失败(img-uMucAKn8-1567223060694)(/upload/images/2019/08/11/1.png)]

EnumSet 是一个抽象类,无法被实例化,但是可以通过静态方法获取该类的实例。

public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E>
    implements Cloneable, java.io.Serializable

EnumMap 类结构图如下:

[外链图片转存失败(img-FTj714ba-1567223060716)(/upload/images/2019/08/11/2.png)]

EnumMap 定义如下:

public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V>
    implements java.io.Serializable, Cloneable

EnumSet 保证集合中的元素不重复;EnumMap 中的 key 是 enum 类型,而 value 则可以是任意类型。

关于这两个数据结构的使用方法,大家可以参考 JDK 手册。


赠人玫瑰,手留余香~

你所不知道的枚举(flag)? 一直以为自己很了解枚举,用起来很顺手,但发现自己知道的只是一部分,枚举原来还可以这么玩,与flag关联做逻辑操作。 这里主要说的是C#中的内容。 阅读详情

相关推荐

JAVA的枚举

本例和上例的执行结果完全相同。

2301_78297748的博客 2139

还有你不知道的Java枚举特性(上篇)

简介 博文 Java 枚举的本质 跟大家一起学习了 Java 语言中枚举到底是什么,探索其本质和原理。用一句话来概括其本质就是:“Java 中的枚举是一个特殊的 Java 类”,有兴趣的同学可以点击了解上面那篇文章。 今天跟大家一起学习和总结一下 Java 中的枚举的其他特性和用途,由于内容较多,这次的分享分为两篇文章来写,欢迎大家拍砖、指正和交流! 本篇主要内容: Java switch 语句...

CodingMan 656

【第60题】必学的枚举1-枚举的定义和基本特性

枚举

小虚竹的专栏 4万+

枚举类都不知道,还敢说自己会Java?

本文主要针对面试中经常被问到的枚举类的热点、难点由浅入深进行深入分析

Mr_wxc的博客 6249

北京途游游戏后端开发面经

北京途游游戏后端开发面经 我面试岗位是基于Python的后端开发工程师,主要是搞游戏的服务器开发。面试一共分了两轮,之后说是看看其他的候选人再定,感觉凉凉~~ 由于受到此次新型冠状病毒疫情的影响,本次面试采用视频面试的方式,下面是面试的时候面试官提的问题,python的基础知识还是问的比较多的。  一面:(32分钟微信视频)  简单做下自我介绍,   1.说一下你开发过的项目,挑一个说下你都做了...

weixin_45603043的博客 2129

避坑指南:Abaqus网格划分中90%用户会遇到的5个质量陷阱(附解决方案)

本文深入剖析Abaqus网格划分中90%用户会遇到的5个典型质量陷阱,包括单元扭曲、扫掠网格失败、尺寸梯度控制等,并提供工程级解决方案。通过Python脚本和虚拟拓扑等技巧,帮助用户提升网格质量,确保有限元分析结果的可靠性,适用于CAE工程师和仿真分析师。

weixin_29243279的博客 102

java枚举的特点_你一定需要知道的高阶JAVA枚举特性!

JAVA枚举,比你想象中还要有用!我经常发现自己在Java中使用枚举来表示某个对象的一组潜在值。在编译时确定类型可以具有什么值的能力是一种强大的能力,它为代码提供了结构和意义。当我第一次了解枚举时,当时我认为它们只是一个为常量命名的工具,可以很容易地被静态常量字符串ENUM_VAL_NAME所取代。后来我发现我错了。事实证明,Java枚举具有相当高级的特性,可以使代码干净、不易出错,功能强大。让我...

weixin_35740875的博客 143

安检机图像处理避坑指南:从条纹校正到物质分类,那些论文里没写的工程细节

本文深入探讨了双能X射线安检机图像处理中的关键工程实践,从条纹校正到物质分类,揭示了论文中未提及的实用技巧。针对探测器校正、物质分类模糊、伪彩色系统设计等核心问题,提供了动态参数更新、空间上下文分析和自适应色彩映射等解决方案,助力提升安检系统的准确性和鲁棒性。

weixin_30325487的博客 889

java枚举1.8,你一定需要知道的高阶JAVA枚举特性!

JAVA枚举,比你想象中功能还要强大!我经常发现自己在Java中使用枚举来表示某个对象的一组值。在编译时确定类型可以具有什么值的能力是一种强大的能力,它为代码提供了结构和意义。当我第一次了解枚举时,当时我认为它们只是一个为常量命名的工具,可以很容易地被静态常量字符串ENUM_VAL_NAME所取代。后来我发现我错了。事实证明,Java枚举具有相当高级的特性,可以使代码干净、不易出错,功能强大。让...

weixin_28851191的博客 430

华为海思IC设计岗位笔试全解析:物理、电路与工艺三大方向备考指南

本文全面解析华为海思IC设计岗位笔试的物理、电路与工艺三大方向备考要点。针对物理设计方向,重点讲解半导体能带理论、载流子输运机制等核心考点;电路设计方向涵盖Verilog语法、UVM验证等关键技术;工艺方向则深入探讨FinFET工艺、光刻技术等前沿知识。提供高效备考策略和应试技巧,助力考生提升通过率。

weixin_29196613的博客 1089

Unity2D像素刀光实现:粒子方向控制与像素级渲染规范

像素风游戏中的刀光特效并非普通粒子动画,而是需严格遵循像素艺术原理的视觉暂留模拟。其核心在于将‘瞬时切割感’转化为程序可执行的渲染逻辑:通过禁用纹理滤波保障1:1像素锐度,绑定刀锋向量控制粒子运动方向,限定≤0.15秒生命周期匹配人眼暂留阈值,并采用Stretched Billboard实现动态拉伸拖影。该方案兼顾美术语义(如直劈、横扫、突刺)与工程约束(Sorting Layer分层、对象池复用、单粒子GPU优化),广泛适用于Unity2D平台的动作反馈系统,尤其适配《空洞骑士》《死亡细胞》类高节奏像素R

weixin_32390647的博客 286

java定义枚举并赋值_java中枚举的特性是什么?如何赋值?

上次已经为大家介绍过java枚举的概念是什么的主要内容了。今天再来为大家介绍一些相关的知识,也是关于java枚举的一些内容,也就是它的特性以及如何赋值,一起来了解一下吧。首先说一下,java中枚举的特性是什么?枚举的特性,归结起来就是一句话:除了不能继承,基本上可以将enum看做一个常规的类。但是这句话需要拆分去理解。1.我们都知道,枚举是可以添加方法的,枚举值默认为从0开始的有序数值 。那么问题...

weixin_32821643的博客 3599

Unity资源提取实战指南:工具、工程与效率三维框架

Unity资源提取是游戏维护、外包接手和逆向分析中的基础技术动作,其本质是理解Unity序列化机制与资源加载流程。核心原理在于解析SerializedFile结构、TypeTree类型树及Addressables/AssetBundle双轨架构;技术价值体现在打破加密/压缩/混淆导致的资源不可见性,支撑美术还原、性能优化与项目交接;典型应用场景包括老项目资产抢救、AR仿真数据导出、手游换皮资源复用等。本文聚焦Unity 2019.4+现代管线,深度融合AssetRipper内存注入与三层穿透法,提供可复用的

weixin_30699955的博客 316

枚举概念与特性

enum 全称为 enumeration, 是 JDK 1.5 中引入的新特性,通过关键字enum来定义枚举类

zhuge_long的专栏 1378

基于STM32F1XX 、HAL库的LTR-303ALS-01 环境光传感器驱动应用C语言程序设计

printf("制造商ID: 0x%02X\r\n", LTR303_ReadManufacID());printf("器件ID: 0x%02X\r\n", LTR303_ReadPartID());LTR-303ALS-01是一款数字环境光传感器(ALS),由Lite-On公司生产。printf("LTR-303ALS初始化失败!printf("LTR-303ALS初始化成功!printf("数据无效\r\n");* @param mode: 0-待机, 1-激活。

PP_Cottage的博客 1034

图神经网络实战(21)——图神经网络的可解释性

在本节中,我们探讨了应用于图神经网络 (Graph Neural Networks, GNN) 的可解释性人工智能 (Explainable Artificial Intelligence, XAI) 技术。可解释性是许多领域的关键要素,可以帮助我们建立更好的模型。我们介绍了不同的局部解释技术,并重点讨论了 GNNExplainer (基于扰动的方法),在图分类任务中应用 GNNExplainer。

盼小辉丶的博客 9611

java enum 性能,你一定需要知道的高阶JAVA枚举特性!

JAVA枚举,比你想象中还要有用!我经常发现自己在Java中使用枚举来表示某个对象的一组潜在值。在编译时确定类型可以具有什么值的能力是一种强大的能力,它为代码提供了结构和意义。当我第一次了解枚举时,当时我认为它们只是一个为常量命名的工具,可以很容易地被静态常量字符串ENUM_VAL_NAME所取代。后来我发现我错了。事实证明,Java枚举具有相当高级的特性,可以使代码干净、不易出错,功能强大。让我...

weixin_42116921的博客 378

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

java——枚举

本例和上例的执行结果完全相同。

zjx1415926的博客 1318

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

3 枚举怎么船只_你一定需要知道的高阶JAVA枚举特性!

JAVA枚举,比你想象中功能还要强大!我经常发现自己在Java中使用枚举来表示某个对象的一组值。在编译时确定类型可以具有什么值的能力是一种强大的能力,它为代码提供了结构和意义。当我第一次了解枚举时,当时我认为它们只是一个为常量命名的工具,可以很容易地被静态常量字符串ENUM_VAL_NAME所取代。后来我发现我错了。事实证明,Java枚举具有相当高级的特性,可以使代码干净、不易出错,功能...

weixin_28894541的博客 78

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

初探Java枚举类

目录1.何为枚举2.枚举本质3.枚举特性3.1基本特性3.2枚举方法3.3 枚举接口3.4 获取枚举元素3.5 状态机4.枚举工具类4.1EnumSet4.2EnumMap5.总结 1.何为枚举 枚举是一种数据类型,具有集合的一些特点,可以存放多个元素,但存储对象有限且固定,枚举也有比较常见的使用场景。如性别(男、女),颜色(红、黄、蓝),星期(星期一、星期二…星期日)均可以使用枚举存储。 2.枚举本质 从源码角度: public abstract class Enum<E extends Enum

增量星球 1710

Java 枚举 新特性

随着JDK版本的迭代,Java的enum不仅在类型安全上更加强大,还与switch语句和表达式、StreamAPI等其他特性紧密结合。switch表达式和对null值的支持让枚举的使用更加灵活,开发者可以更简洁地处理各种逻辑,提高代码的可读性和可维护性。通过合理使用这些特性,我们可以编写更清晰、高效的代码,将Java的强大特性充分发挥出来。

四楼没电梯的专栏 1386

java enum 性能_你一定需要知道的高阶JAVA枚举特性!

JAVA枚举,比你想象中还要有用!我经常发现自己在Java中使用枚举来表示某个对象的一组潜在值。在编译时确定类型可以具有什么值的能力是一种强大的能力,它为代码提供了结构和意义。当我第一次了解枚举时,当时我认为它们只是一个为常量命名的工具,可以很容易地被静态常量字符串ENUM_VAL_NAME所取代。后来我发现我错了。事实证明,Java枚举具有相当高级的特性,可以使代码干净、不易出错,功能强大。让我...

weixin_34404808的博客 325

Java 枚举

Java 枚举是一种强大的工具,其本质上是一个继承自 java.lang.Enum 的类,用于定义一组固定的常量,每个枚举常量都是该枚举类的一个实例。枚举不仅提供了类型安全性,还可以像普通类一样拥有字段、方法和构造函数。枚举的使用场景非常广泛,包括表示一组相关的常量、实现单例模式等。通过合理使用枚举,可以使代码更加清晰、安全和易于维护。

qq_33807380的博客 1301

【Java】深入剖析Java枚举类

枚举类是Java 5引入的,在Java 5之前,Java并没有内置的枚举类型,只能通过自定义类来实现类似枚举的功能。...Java 枚举类是一种特殊类型的数据结构,一般用来存储定义一些字符串,数字等数据结构。枚举类中的每个常量都称为枚举常量。枚举类在Java中使用关键字enum定义。CONSTANT1,CONSTANT2,CONSTANT3,...其中,EnumClass为枚举类的名称,CONSTANT1、CONSTANT2、CONSTANT3等为枚举常量的名称。

锥栗的博客 1721
上一篇: 跳绳的故事
下一篇: 微服务: 写注册和登录的接口
veryitman
博客等级 码龄16年 472粉丝 310原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值