JDK源码Enum类原理及代码实例解析

正文

一 概述

枚举类型是 JDK 5 之后引进的一种非常重要的引用类型,可以用来定义一系列枚举常量,使用 enum 来表示枚举可以更好地保证程序的类型安全和可读性

实际上在使用关键字enum创建枚举类型并编译后,编译器会为我们生成一个相关的类,这个类继承了Java API中的java.lang.Enum类,

也就是说通过关键字enum创建枚举类型在编译后事实上也是一个类类型而且该类继承自java.lang.Enum类

使用举例

public class EnumTest {

  enum MyCode{
    ONE("1","编码一"),
    TWO("2","编码二");

    private String code;
    private String name;

    MyCode(String code, String name) {
      this.code = code;
      this.name = name;
    }
  }

  public static void main(String[] args) {
    // 获取一个枚举实例
    MyCode one = MyCode.valueOf(MyCode.class, "ONE");
    // 可以调用Enum类中的实例方法
    one.compareTo(MyCode.TWO);
  }
}

二 源码分析

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

    //枚举常量的名称
    private final String name;

    //返回此枚举常量的名称,与其枚举声明中声明的完全相同
    public final String name() {
      return name;
    }

    //此枚举常量的序数(它在枚举声明中的位置,其中初始常量的序数为零)
    private final int ordinal;

    //返回序号
    public final int ordinal() {
      return ordinal;
    }

    // 构造器
    protected Enum(String name, int ordinal) {
      this.name = name;
      this.ordinal = ordinal;
    }

    //返回声明中包含的此枚举常量的名称
    public String toString() {
      return name;
    }

    //果指定的对象等于此枚举常量,则返回true。
    public final boolean equals(Object other) {
      return this==other;
    }

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

    // 无法被克隆
    protected final Object clone() throws CloneNotSupportedException {
      throw new CloneNotSupportedException();
    }

    //将此枚举与指定的枚举序号进行比较
    public final int compareTo(E o) {
      Enum<?> other = (Enum<?>)o;
      Enum<E> self = this;
      if (self.getClass() != other.getClass() && // optimization
          self.getDeclaringClass() != other.getDeclaringClass())
        throw new ClassCastException();
      return self.ordinal - other.ordinal;
    }

    //返回与此枚举常量的枚举类型相对应的Class对象
    @SuppressWarnings("unchecked")
    public final Class<E> getDeclaringClass() {
      Class<?> clazz = getClass();
      Class<?> zuper = clazz.getSuperclass();
      return (zuper == java.lang.Enum.class) ? (Class<E>)clazz : (Class<E>)zuper;
    }

    /**
     * 返回具有指定名称的指定枚举类型的枚举常量。
     * 该名称必须与用于声明此类型的枚举常量的标识符完全一致。
     * 请注意,对于特定枚举类型T ,
     * 有两个隐式声明方法可以直接使用:
     *   public static T valueOf(String)  根据名称获取单个枚举类型
     *   public static T[] values()  获取所有枚举类型数组
     */
    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 constant " + enumType.getCanonicalName() + "." + name);
    }

    //枚举类不能有 finalize 方法
    protected final void finalize() { }

    //防止反序列化
    private void readObject(ObjectInputStream in) throws IOException,
        ClassNotFoundException {
      throw new InvalidObjectException("can't deserialize enum");
    }
    private void readObjectNoData() throws ObjectStreamException {
      throw new InvalidObjectException("can't deserialize enum");
    }
  }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • C# IQueryable及IEnumerable区别解析

    在使用EF查询数据的时候,我们常用的查询数据方式有linq to sql,linq to object, 查询返回的结果有两种类型:IQueryable.IEnumerable,两者内部的处理机制是完全不同的. 清楚认识,这里也是一个数据查询的优化点. 在System.linq命名空间,有两个静态类:Queryable和Enumerable. 在System.linq.Queryable中,参数接收的是一个表达式类型,返回IQueryable接口 public static IQueryable

  • Python range与enumerate函数区别解析

    在迭代中enumerate比range更能灵活,一般情况下尽量用erumerate,下面举例说明: 先来看range的使用: city_list = ['beijing', 'shanghai', 'tianjing', 'wuhan'] # 用range将元素打印出来 # 直接打印,不用range for city in city_list: print('this is %s' % city) # 用下标打印 for i in range(len(city_list)): city = ci

  • mybatis-plus使用@EnumValue处理枚举类型的示例代码

    自mybatis3.1.0开始,如果你无需使用原生枚举,可配置默认枚举来省略扫描通用枚举配置 默认枚举配置 1.配置文件配置枚举所在的包 #配置枚举 支持通配符 * 或者 ; 分割 mybatis-plus.type-enums-package=com.iscas.biz.mp.test.model.enums mybatis-plus.configuration.default-enum-type-handler=org.apache.ibatis.type.EnumOrdinalTypeHa

  • JavaScript enum枚举类型定义及使用方法

    enum型也被成为枚举类型,它是一种可以将多个常量分组为一个并附加一系列值的类型,使用枚举定义的常量称为枚举器列表,默认情况下,枚举器从零开始按顺序编号.本篇文章给大家介绍关于JavaScript中枚举类型的使用. JavaScript中enum(枚举类型)是什么? JavaScript中是没有枚举类型的,除了JavaScript以外的语言都有enum这个关键词,但为了在JavaScript中使用枚举变量,我们必须自己创建它. 下面我们就来看如何在JavaScript中定义enum(枚举类型)

  • 浅谈Java中是否直接可以使用enum进行传输

    背景 我们在进行传输的时候 会有一些状态值,如Status为1代表删除,为0代表失败或者怎么样的.只传输一个)0或者1过去给第三方(此处不包括给前端),如果没有契约第三方会不认识你这个是什么意思,那我们在平时写业务逻辑的时候使用枚举很轻易就知道了什么状态什么值.所以我们在构建DTO对象的时候里面放一个枚举来表示. 首先在阿里的规范里是这样说的: [强制]二方库里可以定义枚举类型,参数可以使用枚举类型,但是接口返回值不允许使用枚举类型或者包含枚举类型的 POJO 对象. 那到底为啥不能用呢? 枚举

  • C++枚举类型enum与enum class的使用

    一.关于枚举类型 1. 什么是枚举类型? 答:如果一个变量只有几种可能的值,那么就可以定义为枚举类型,比如:性别只有男和女,那么就可以将性别定义为一种枚举类型,其中男和女就是性别所包含的变量.所谓"枚举"是指将变量的值一一列举出来,变量的值只能在列举出来的值的范围内.在C++中,枚举类型分为不限定作用域(enum)和限定作用域(enum class). 2. enum与enum class的区别? (为什么需要限定作用域?) 答:枚举作用域是指枚举类型成员名字的作用域,起自其声明之处,

  • Python enumerate() 函数如何实现索引功能

    1.描述: enumerate()函数用于将一个可遍历的数据对象(如列表,元组,字符串)组合为一个索引序列,同时列出数据和数据索引(下标),一般用于for循环当中 2.语法 enumerate(sequence, [start=0]) 3.参数: sequence:一个序列,迭代器或其他支持迭代对象 start:可选参数,下标起始位置,默认从索引0开始 4.返回值 返回enumerate(枚举)对象 5.实例 list1 = [10,20,30,40,"maple","yf&

  • Python enumerate内置库用法解析

    这篇文章主要介绍了Python enumerate内置库用法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 使用enumerate,可以自动进行索引下标的赋值,本例代码中使用enumerate,进行excel单元格的赋值操作. 代码如果重复被调用,可将该代码封装成类进行使用 import openpyxl #加载excel文件 wb = openpyxl.load_workbook('test_datas/test_cases.xlsx')

  • C语言枚举(enum)和联合(union)实例分享

    使用enum进行定义 /* 枚举类型演示 */ #include <stdio.h> int main() { enum /*季节*/ {CHUN, XIA = 5, QIU, DONG}; printf("QIU是%d\n", QIU); } 使用union联合进行定义 /* 联合演示 */ #include <stdio.h> typedef union{ int val; float fval1; } tmp; int main(){ tmp utmp =

  • JDK源码Enum类原理及代码实例解析

    正文 一 概述 枚举类型是 JDK 5 之后引进的一种非常重要的引用类型,可以用来定义一系列枚举常量,使用 enum 来表示枚举可以更好地保证程序的类型安全和可读性 实际上在使用关键字enum创建枚举类型并编译后,编译器会为我们生成一个相关的类,这个类继承了Java API中的java.lang.Enum类, 也就是说通过关键字enum创建枚举类型在编译后事实上也是一个类类型而且该类继承自java.lang.Enum类 使用举例 public class EnumTest { enum MyCo

  • React源码state计算流程和优先级实例解析

    目录 setState执行之后会发生什么 根据组件实例获取其 Fiber 节点 创建update对象 将Update对象关联到Fiber节点的updateQueue属性 发起调度 processUpdateQueue做了什么 变量解释 构造本轮更新的 updateQueue 更新 workInProgress 节点 总结 update对象丢失问题 为什么会丢失 如何解决 state计算的连续性 问题现象 如何解决 setState执行之后会发生什么 setState 执行之后,会执行一个叫 en

  • Vue Render函数原理及代码实例解析

    简单的说,在vue中我们使用模板HTML语法组建页面的,使用render函数我们可以用js语言来构建DOM 因为vue是虚拟DOM,所以在拿到template模板时也要转译成VNode的函数,而用render函数构建DOM,vue就免去了转译的过程. 当使用render函数描述虚拟DOM时,vue提供一个函数,这个函数是就构建虚拟DOM所需要的工具.官网上给他起了个名字叫createElement.还有约定的简写叫h 虽然在render里使用createElement函数创建DOM节点不是很直观

  • MyBatis缓存实现原理及代码实例解析

    一.一级缓存(本地缓存) sqlSession级别的缓存.一级缓存是一直开启的:SqlSession级别的一个Map与数据库同一次会话期间查询到的数据会放在本地缓存中.以后如果需要获取相同的数据,直接从缓存中拿,没必要再去查询数据库: 一级缓存失效情况(没有使用到当前一级缓存的情况,效果就是,还需要再向数据库发出查询): 1.sqlSession不同 2.sqlSession相同,查询条件不同.(当前一级缓存中还没有这个数据) 3.sqlSession相同,两次查询之间执行了增删改操作(这次增删

  • 通过JDK源码角度分析Long类详解

    概况 Java的Long类主要的作用就是对基本类型long进行封装,提供了一些处理long类型的方法,比如long到String类型的转换方法或String类型到long类型的转换方法,当然也包含与其他类型之间的转换方法.除此之外还有一些位相关的操作. Java long数据类型 long数据类型是64位有符号的Java原始数据类型.当对整数的计算结果可能超出int数据类型的范围时使用. long数据类型范围是-9,223,372,036,854,775,808至9,223,372,036,85

  • JDK源码之线程并发协调神器CountDownLatch和CyclicBarrier详解

    目录 引言 CountDownLatch 使用场景 底层实现原理 初始化 计数器递减 阻塞线程 CyclicBarrier 使用场景 底层实现原理 初始化 阻塞等待 总结 引言 那么在程序的世界中是如何对这种协调关系进行描述的呢?今天就和大家聊聊Java大神Doug Lea在并发包中如何通过CountDownLatch和CyclicBarrier实现任务协调的代码描述. CountDownLatch 我相信大家都知道好代码的一个重要特性就是代码中类.变量等的命名可以做到顾名思义,也就是说看到命名

  • 通过JDK源码学习InputStream详解

    概况 本文主要给大家介绍了通过JDK源码学习InputStream的相关内容,JDK 给我们提供了很多实用的输入流 xxxInputStream,而 InputStream 是所有字节输入流的抽象.包括 ByteArrayInputStream .FilterInputStream .BufferedInputStream .DataInputStream 和 PushbackInputStream 等等.下面话不多说了,来一起看看详细的介绍吧. 如何阅读JDK源码. 以看核心虚拟机(hotsp

  • Java从JDK源码角度对Object进行实例分析

    Object是所有类的父类,也就是说java中所有的类都是直接或者间接继承自Object类.比如你随便创建一个classA,虽然没有明说,但默认是extendsObject的. 后面的三个点"..."表示可以接受若干不确定数量的参数.老的写法是Objectargs[]这样,但新版本的java中推荐使用...来表示.例如 publicvoidgetSomething(String...strings)(){} object是java中所有类的父类,也就是说所有的类,不管是自己创建的类还是

  • JDK源码分析之String、StringBuilder和StringBuffer

    前言 本文主要介绍了关于JDK源码分析之String.StringBuilder和StringBuffer的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧 String类的申明 public final class String implements java.io.Serializable, Comparable<String>, CharSequence {-} String类用了final修饰符,表示它不可以被继承,同时还实现了三个接口, 实现Serializa

  • 分析HashMap 的 JDK 源码

    缘由:今天好友拿着下面的代码,问我为什么 Map.Entry 这个接口没有实现 getKey() 和 getValue() 方法,却可以使用,由此,开启了一番查阅 JDK 源码的旅途-. Map map = new HashMap(); map.put(1, "张三"); map.put(2, "李四"); map.put(3, "王五"); map.put(4, "赵六"); map.put(5, "钱七"

随机推荐