Java中枚举的线程安全性及序列化问题

2023-05-16

一、枚举是如何保证线程安全的

要想看源码,首先得有一个类吧,那么枚举类型到底是什么类呢?是enum吗?答案很明显不是,enum就和class一样,只是一个关键字,他并不是一个类,那么枚举是由什么类维护的呢,我们简单的写一个枚举:

public enum t {
    SPRING,SUMMER,AUTUMN,WINTER;
}

然后我们使用反编译,看看这段代码到底是怎么实现的,反编译后代码内容如下:

public final class T extends Enum
{
    private T(String s, int i)
    {
        super(s, i);
    }
    public static T[] values()
    {
        T at[];
        int i;
        T at1[];
        System.arraycopy(at = ENUM$VALUES, 0, at1 = new T[i = at.length], 0, i);
        return at1;
    }

    public static T valueOf(String s)
    {
        return (T)Enum.valueOf(demo/T, s);
    }

    public static final T SPRING;
    public static final T SUMMER;
    public static final T AUTUMN;
    public static final T WINTER;
    private static final T ENUM$VALUES[];
    static
    {
        SPRING = new T("SPRING", 0);
        SUMMER = new T("SUMMER", 1);
        AUTUMN = new T("AUTUMN", 2);
        WINTER = new T("WINTER", 3);
        ENUM$VALUES = (new T[] {
            SPRING, SUMMER, AUTUMN, WINTER
        });
    }
}

通过反编译后代码我们可以看到,public final class T extends Enum,说明,该类是继承了Enum类的,同时final关键字告诉我们,这个类也是不能被继承的。当我们使用enmu来定义一个枚举类型的时候,编译器会自动帮我们创建一个final类型的类继承Enum类,所以枚举类型不能被继承,我们看到这个类中有几个属性和方法。

我们可以看到:

public static final T SPRING;
public static final T SUMMER;
public static final T AUTUMN;
public static final T WINTER;
private static final T ENUM$VALUES[];
static
{
	SPRING = new T("SPRING", 0);
	SUMMER = new T("SUMMER", 1);
	AUTUMN = new T("AUTUMN", 2);
	WINTER = new T("WINTER", 3);
	ENUM$VALUES = (new T[] {
		SPRING, SUMMER, AUTUMN, WINTER
	});
}

都是static类型的,因为static类型的属性会在类被加载之后被初始化,我们在深度分析Java的ClassLoader机制(源码级别)和Java类的加载、链接和初始化两个文章中分别介绍过,当一个Java类第一次被真正使用到的时候静态资源被初始化、Java类的加载和初始化过程都是线程安全的。所以,创建一个enum类型是线程安全的。

二、枚举自己处理序列化

以前的所有的单例模式都有一个比较大的问题,就是一旦实现了Serializable接口之后,就不再是单例得了,因为,每次调用 readObject()方法返回的都是一个新创建出来的对象有一种解决办法就是使用readResolve()方法来避免此事发生。但是,为了保证枚举类型像Java规范中所说的那样,每一个枚举类型极其定义的枚举变量在JVM中都是唯一的,在枚举类型的序列化和反序列化上,Java做了特殊的规定。

大概意思就是说:在序列化的时候Java仅仅是将枚举对象的name属性输出到结果中,反序列化的时候则是通过java.lang.Enum的valueOf方法来根据名字查找枚举对象。同时,编译器是不允许任何对这种序列化机制的定制的,因此禁用了writeObject、readObject、readObjectNoData、writeReplace和readResolve等方法。 我们看一下这个valueOf方法:

public static <T extends Enum<T>> T valueOf(Class<T> enumType,String name) {  
	T result = enumType.enumConstantDirectory().get(name);  
	if (result != null)  
		return result;  
	if (name == null)  
		throw new NullPointerException("Name is null");  
	throw new IllegalArgumentException(  
		"No enum const " + enumType +"." + name);  
}

从代码中可以看到,代码会尝试从调用enumType这个Class对象的enumConstantDirectory()方法返回的map中获取名字为name的枚举对象,如果不存在就会抛出异常。再进一步跟到enumConstantDirectory()方法,就会发现到最后会以反射的方式调用enumType这个类型的values()静态方法,也就是上面我们看到的编译器为我们创建的那个方法,然后用返回结果填充enumType这个Class对象中的enumConstantDirectory属性。

所以,JVM对序列化有保证。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java中枚举的线程安全性及序列化问题 的相关文章

随机推荐

  • 奥比中光Orbbec Astra Pro RGBD 3D视觉传感器在ROS(indigo和kinetic)使用说明 rgb depth同时显示

    Orbbec Astra Pro传感器在ROS xff08 indigo和kinetic xff09 使用说明 rgb depth同时显示 这款摄像头使用uvc输入彩色信息 xff0c 需要libuvc和libuvc ros这样才能在ROS
  • 【BUG解决】sudo apt-get update 报错 E: The repository ‘http://xxx Release‘ does not have a Release file.

    BUG描述 前两天在虚拟机Vmware中安装了Ubuntu18 04操作系统 xff0c 因为需要安装其他工具 所以想着执行命令 sudo apt get update 更新一下系统 xff0c 以便进行安装 结果出现 E The repo
  • python isinstance(), stack,判断list, dict, tuple为空

    Problem Nikola likes to categorize everything in sight One time Stephan gave him a label maker for his birthday and the
  • 路径跟踪算法之PID路径跟踪与PP跟踪

    路径跟踪算法之PID路径跟踪与PP跟踪 1路径跟踪原理2 常见的路径跟踪算法2 1 Pure puresuit pp 纯跟踪2 2 PID 跟踪 1路径跟踪原理 在运用好的路径规划算法 xff0c 规划好一条从起点到目标点最优的路径后 xf
  • 深入详解PID三项的作用与特性(抛开公式,以常识认识PID)

    深入探讨PID三项作用与特性 xff08 纯以常识方式对PID进行数学理论分析 xff09 1 经典PID的理解 xff08 抛弃公式 xff0c 以常识认识PID xff09 源文献 PID指的就是比例 积分 微分三项的结合 xff0c
  • ADRC自抗扰控制,有手就行

    ADRC自抗扰控制 xff0c 有手就行 关于ADRC的优点本人不会赘述 xff0c 毕竟作为一个ADRC算法都推导不出来的应用工程师 xff0c 最希望看到的就是有手就行的操作方法 ARC的缺点就显而易见 xff0c 就是参数多 xff0
  • nuScenes数据集详细介绍

    本文为博主原创文章 xff0c 未经博主允许不得转载 本文为专栏 python三维点云从基础到深度学习 系列文章 xff0c 地址为 https blog csdn net suiyingy article details 12401771
  • fegin调用的时候数据格式转换为linkedhashmap

    在spring cloud项目开发中 xff0c 使用fegin进行远程调用 1 接口服务方返回类型为Map String Object 类型 2 接口调用方返回值类型也是Map String Object 3 通过fegin调用之后返回的
  • 一个字符串截取函数c语言

    刚开始学习c语言 xff0c 标准库中总是有很多函数没有 xff0c string h中的字符串处理函数好像不是很多 xff0c 在做栈的例子用需要用到一个字符串按位置截取的函数 xff0c 就自己写一个 xff0c 超简单 char su
  • RAF_DB数据集分类_3

    混淆矩阵 这里ECANet太长了 xff0c 我这里直接利用resnet代替一下 xff0c 你可以直接替换 xff0c 然后把权重对应好即可 xff0c 这只是一个简单的混淆矩阵生成 xff0c 没有太多美化 span class tok
  • docker镜像的创建

    目录 基于现有镜像创建 首先启动一个镜像 xff0c 在容器里做修改 然后将修改后的容器提交为新的镜像 xff0c 需要使用该容器的ID号创建新镜像 基于本地模板创建 导入镜像 基于Dockerfile创建 联合文件系统 xff08 Uni
  • ROS源码分析--子话题-catkin

    catkin简介 catkin简介 packagexml 格式1格式2 CMakeListtxtmeta package典型ROS应用添加自定义message文件 修改packagexml修改CMakeListtxt find packag
  • vnc安装和开机自启设置

    一 安装VNC 键入以下命令以在 Ubuntu 服务器上安装 TigerVNC xff1a sudo apt install tigervnc standalone server tigervnc common 现在安装了 VNC 服务器
  • 【Linux】线程安全篇Ⅰ

    文章目录 0 概述1 线程不安全举例1 1 前提知识铺垫1 2 场景模拟1 3 代码模拟 2 互斥2 1 什么是互斥2 2 互斥锁的原理 amp amp 特性2 3 互斥锁的计数器如何保证原子性2 4 互斥锁的接口2 4 1 初始化接口2
  • PX4/APM/飞控的学习笔记前言-Cxm

    开始了 开始了 终于有时间可以学习飞控了 此文章是用来当目录 我会持续更新我的学习之旅 希望能对各位有所帮助 如果有错误的地方还请各位前辈指点 此帖持续更新后续内容 其实从21年的一月就开始学习飞控一开始是从PX4开始学习 但是因为对liu
  • kubernetes 中文版

    这个文档非常好用 xff0c 建议收藏 无水印版 https pan baidu com s 1LSI46GBENd90Z06FnuaKmw lukb
  • SimpleBGC三轴云台用户手册

    SimpleBGC三轴云台用户手册 V1 00 硬件平台 xff1a STorM BGC V1 31 软件框架 xff1a SimpleBGC V1 00 本方案是采用俄版STorM BGC硬件平台 xff0c 软件采用SimpleBGC架
  • typedef和define有什么区别

    typedef和define都是替一个对象取一个别名 xff0c 以此增强程序的可读性 xff0c 区别如下 xff1a xff08 1 xff09 原理不同 define是C语言中定义的语法 xff0c 是预处理指令 xff0c 在预处理
  • 接口返回报错 resource notfound,plrase check path

    1 报错原因 post请求的content type application x www form urlencoded 但是请求体中设置的是json数据 34 date 34 34 2022 01 01 34 34 inclTransfe
  • Java中枚举的线程安全性及序列化问题

    一 枚举是如何保证线程安全的 要想看源码 xff0c 首先得有一个类吧 xff0c 那么枚举类型到底是什么类呢 xff1f 是enum吗 xff1f 答案很明显不是 xff0c enum就和class一样 xff0c 只是一个关键字 xff