先思考一个问题

简介: 在 Java 编程中,枚举(enum)是一种常用的数据类型。尽管我们在定义 enum 类时并未显式声明 `values()` 和 `valueOf(String)` 方法,但依然可以直接使用它们。这是因为 Java 编译器在编译 enum 类时,会自动为其添加这些方法。例如,一个简单的枚举类 `Weekday` 定义如下:```javapublic enum Weekday { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;}```

先思考一个问题:我们在enum类里,可以直接使用 values() 或 valueOf(String name) 方法,我们也没有在enum类里定义这两个方法,怎么就能直接使用呢?

这里先按下不表。

下面是正文。

回到顶部
§2 enum类及其编译后的字节码
在java编程中,我们经常会定义和使用枚举。

简单的enum类及其字节码概览
一个简单的 enum 类定义如下:

public enum Weekday {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;
}

Java Enum类型的语法结构尽管和java类的语法不一样,应该说差别比较大。但是经过编译器编译之后产生的是一个class文件。我们反编译该class文件后,可以看到实际上是生成了一个class类,该类继承了 java.lang.Enum,其中包括了常量和方法。

首先,编译 Weekday.java 文件:

javac Weekday.java

经过 javac 编译后得到一个名字为Weekday.class的class字节码文件。然后,使用 javap 命令查看生成的字节码文件源码:

javap -c Weekday.class

生成的字节码文件源码可能会类似于下面的内容(这是经过简化和部分省略的例子):

复制代码
Compiled from "Weekday.java"
public final class Weekday extends java.lang.Enum {
public static final Weekday MONDAY;
public static final Weekday TUESDAY;
public static final Weekday WEDNESDAY;
public static final Weekday THURSDAY;
public static final Weekday FRIDAY;
public static final Weekday SATURDAY;
public static final Weekday SUNDAY;

static {};
private Weekday();
public static Weekday[] values();
public static Weekday valueOf(java.lang.String);
}
复制代码

这段字节码文件源码显示了 Weekday 枚举类中的常量以及一些生成的方法,例如 values() 和 valueOf(String) 等。实际的字节码文件源码会更加复杂,其中包含了更多的细节和信息。

所以实际上Enum类型就是以Java类来实现的,没有什么新的特点,只不过java编译器帮我们做了语法的解析和编译。

附图:在IDEA Terminal窗口中所执行的命令

功能丰富的enum类 及其字节码详解
我们知道,enum 类型可以包含除了默认的 name() 和 ordinal() 方法之外的扩展信息。我们可以为每个枚举常量添加字段、构造函数、方法等,使得枚举类型更加灵活和功能丰富。

我们看下面的 Weekday枚举。

复制代码
public enum Weekday {
MONDAY(1, "星期一"), TUESDAY(2, "星期二"), WEDNESDAY(3, "星期三"), THURSDAY(4, "星期四"), FRIDAY(5, "星期五"), SATURDAY(6, "星期六"), SUNDAY(7, "星期日");

private final int dayNo;
private final String name;

private Weekday(int dayNo, String name) {
    this.dayNo = dayNo;
    this.name = name;
}

public static Weekday getEnum(int dayNo) {
    for (Weekday d : values()) {
        if (d.dayNo == dayNo)
            return d;
    }
    return null;
}

}
复制代码

下面是javap打印出来的完整的字节码源码:

View Code

由字节码可见,javac为这个class生成了7个Weekday类型的公共静态常量MODAY、TUESDAY、...、SUNDAY,它们在这个class的static代码块中得到初始化。

static代码块的大致逻辑是:

  1. 创建类型为Weekday的实例 new Weekday("MONDAY", 0, 1, "星期一"),赋值给静态变量MONDAY。见下方字节码片段。

    View Code

  2. 同第一步,依次创建实例、给静态变量TUESDAY、...、SUNDAY赋值。

  3. 调用静态方法 values()。

  4. 给静态变量 $VALUES 赋值。

回到顶部
§3 java.lang.Enum类介绍
javadoc及类声明

/
This is the common base class of all Java language enumeration types. More information about enums, including descriptions of the implicitly declared methods synthesized by the compiler, can be found in section 8.9 of The Java™ Language Specification.
Note that when using an enumeration type as the type of a set or as the type of the keys in a map, specialized and efficient set and map implementations are available.
Since: 1.5
See Also: Class.getEnumConstants(), java.util.EnumSet, java.util.EnumMap
/
public abstract class Enum>
implements Comparable, Serializable {

//代码效果参考:http://www.mwgw.cn/sitemap/post.html
Enum类的成员

从中我们get到:

① Enum是所有Java枚举类型的公共基类。

② Enum是一个抽象类,我们不能new一个Enum实例。

Enum的默认受保护构造器Enum(String, int),第一个参数是我们定义的枚举常量的名称,对应的field是Enum#name,第二个参数指的是枚举的顺序,对应的field是Enum#ordinal。

Enum定义了valueOf方法,用以根据枚举常量的name来获取枚举常量。

枚举虽然是class,但是并不支持继承

尝试继承自枚举时,会提示: Cannot inherit from enum 'jstudy.enumsinterface.MyEnum'
尝试继承自class类时,会提示: No extends clause allowed for enum
这大概也佐证了enum是一种特殊的class。

不过,枚举支持实现接口。我们项目中,几乎所有enum都实现了EnumAbility这个interface。这体现了java对面向接口编程理论的最强大的支持。

回到顶部
§4 回到文章开头的问题
回到文章开头的问题。为什么我们在创建的enum类里可以直接访问 values() 或 valueOf(String) 方法呢?

从上面的字节码源码可以看出来,这2个方法是 java编译器 给加上的。换句话说,在 Java 中,所有的枚举类型都是继承自 java.lang.Enum 类。Java编译器在编译Enum 类时,会生成一些方法,其中包括 values() 和 valueOf(String name) 方法。因为这些方法是在编译时由编译器自动生成并添加到枚举类中的,所以,我们在任何枚举类中都可以直接使用这两个方法,而无需显式地在枚举类中定义它们。

就像我们在model类上添加 lombok工具的 @Data 注解,就可以使用这个model对象的getter和setter。

就像我们在枚举类上添加 enumgen工具的 @GetByEnum 注解,就可以使用 getBeanByCode(code)。

相关文章
|
3月前
|
算法 Java 数据安全/隐私保护
国密加密算法简介
国密指国家密码局认定的国产密码算法,主要包括SM1、SM2、SM3、SM4等,并持续完善。SM1是对称加密算法,加密强度与AES相当,需加密芯片支持;SM2是非对称加密,基于ECC算法,签名和密钥生成速度优于RSA;SM3为杂凑算法,安全性高于MD5;SM4为对称加密算法,用于无线局域网标准。本文提供使用Java和SpringBoot实现SM2和SM4加密的示例代码及依赖配置。更多国密算法标准可参考国家密码局官网。
314 1
|
3月前
|
安全 关系型数据库 MySQL
Navicat工具设置MySQL权限的操作指南
通过上述步骤,您可以使用Navicat有效地为MySQL数据库设置和管理用户权限,确保数据库的安全性和高效管理。这个过程简化了数据库权限管理,使其既直观又易于操作。
451 4
|
4月前
|
Linux Perl
在Linux中,如何停止正在运行的进程?
在Linux中,如何停止正在运行的进程?
|
3月前
|
人工智能 前端开发 Java
Spring Cloud Alibaba AI,阿里AI这不得玩一下
🏀闪亮主角: 大家好,我是JavaDog程序狗。今天分享Spring Cloud Alibaba AI,基于Spring AI并提供阿里云通义大模型的Java AI应用。本狗用SpringBoot+uniapp+uview2对接Spring Cloud Alibaba AI,带你打造聊天小AI。 📘故事背景: 🎁获取源码: 关注公众号“JavaDog程序狗”,发送“alibaba-ai”即可获取源码。 🎯主要目标:
112 0
|
3月前
|
存储 网络安全 开发工具
快速认识和上手云效代码管理应用
要体验云效代码托管Codeup的本地命令行操作和SSH克隆/提交,请先安装Git并配置SSH公钥。登录Codeup后,新建代码库并设置相关信息。可从其他平台导入代码。提交代码支持网页和本地客户端两种方式。库管理员可邀请成员协作,并按需设置角色。此外,Codeup内置代码检测服务,支持自动触发扫描。功能开发完成后,可通过合并请求进行代码评审,确保编码质量。
115 1
|
3月前
|
关系型数据库 分布式数据库 PolarDB
基于PolarDB Ganos的实时时空计算:电子围栏篇
PolarDB是阿里云自主研发的云原生关系型数据库,提供极致弹性、高性能、海量存储及高安全性的数据库服务。PolarDB PostgreSQL版100%兼容PostgreSQL与Oracle语法,集成Ganos云原生时空数据库引擎,支持几何、栅格、轨迹等多种核心功能,实现物理世界时空数据的混合存储与分析。本文介绍的Ganos实时电子围栏计算依托PolarDB PostgreSQL版,展示了其在交通物流、安防、营销等多个领域的应用场景和技术实现细节,包括数据源配置、空间计算函数注册、电子围栏表生成及计算结果存储等步骤。通过Flink实时计算框架,Ganos实现了高效、实时的电子围栏运算
100 0
|
3月前
|
SQL 存储 数据可视化
Ganos H3地理网格能力解析与最佳实践
Ganos H3地理网格是一种基于六边形结构的高效地理空间数据处理技术,适用于物流、社交网络、数据分析及应急响应等多种场景。Ganos H3利用独特的六边形网格体系实现更均匀的数据分布和固定邻居关系,优化了空间数据分析、路径规划等功能。Ganos地理网格引擎支持GeoSOT和H3两种网格,具备丰富的打码方式、高性能查询及聚合分析能力,并能与几何和栅格数据融合,大幅提升了数据处理效率和存储成本效益。借助Ganos H3,企业和开发者可以更好地管理和利用地理空间数据,提高位置相关决策的准确性和效率。
131 0
|
4月前
|
Java 程序员 开发者
我们踩过的Java坑:自定义异常,让你的代码不再“捉急”!
我们踩过的Java坑:自定义异常,让你的代码不再“捉急”!
168 1
|
5月前
|
JSON JavaScript 前端开发
若依修改,若依如何发送get和post请求,发送数据请求的写法,若依请求的API在src的api文件下,建立请求的第一步,在API中新建一个文件,第二步新建JavaScript文件
若依修改,若依如何发送get和post请求,发送数据请求的写法,若依请求的API在src的api文件下,建立请求的第一步,在API中新建一个文件,第二步新建JavaScript文件
|
7月前
|
SQL 缓存 安全
【JavaEE进阶】 #{}和${}
【JavaEE进阶】 #{}和${}