一文看懂Java的枚举(上)

简介: 一文看懂Java的枚举(上)

1 定义

一种数据类型,只包含自定义的特定数据,是一组有共同特性的数据的集合。

创建需要enum关键字,如:

public enum Color {  
    RED, GREEN, BLUE, BLACK, PINK, WHITE;  
}

enum的语法看似与类不同,但它实际上就是一个类。

image.png

把上面的编译成 Gender.class, 然后用 javap -c Gender反编译

image.png

可得到


Gender 是 final 的

Gender 继承自 java.lang.Enum 类

声明了字段对应的两个 static final Gender 的实例

实现了 values() 和 valueOf(String) 静态方法

static{} 对所有成员进行初始化

结合字节码,还原 Gender 的普通类形式

public final class Gender extends java.lang.Enum {
  public static final Gender Male;
  public static final Gender Female;
  private static final Gender[] $VALUES;
  static {
    Male = new Gender("Male", 0);
    Female = new Gender("Female", 1);
    $VALUES = new Gender[] {Male, Female};
  }
  public static Gender[] values() {
    return $VALUE.clone();
  }
  public static Gender valueOf(String name) {
    return Enum.valueOf(Gender.class, name);
  }
}

创建的枚举类型默认是java.lang.enum<枚举类型名>(抽象类)的子类


每个枚举项的类型都为public static final。


上面的那个类是无法编译的,因为编译器限制了我们显式的继承自 java.Lang.Enum 类, 报错 “The type Gender may not subclass Enum explicitly”, 虽然 java.Lang.Enum 声明的是

image.png

这样看来枚举类其实用了多例模式,枚举类的实例是有范围限制的

它同样像我们的传统常量类,只是它的元素是有限的枚举类本身的实例

它继承自 java.lang.Enum, 所以可以直接调用 java.lang.Enum 的方法,如 name(), original() 等。

name 就是常量名称

image.png

original 与 C 的枚举一样的编号

image.png

因为Java的单继承机制,emum不能再用extends继承其他的类。

image.png

可以在枚举类中自定义构造方法,但必须是 private 或 package protected, 因为枚举本质上是不允许在外面用 new Gender() 方式来构造实例的(Cannot instantiate the type Gender)


结合枚举实现接口以及自定义方法,可以写出下面那样的代码

image.png

方法可以定义成所有实例公有,也可以让个别元素独有

需要特别注明一下,上面在 Male {} 声明一个 print() 方法后实际产生一个 Gender 的匿名子类,编译后的 Gender$1,反编译它

image.png

所以在 emum Gender 那个枚举中的成员 Male 相当于是

public static final Male = new Gender$1("Male", 0); //而不是 new Gender("Male", 0)

上面4: Invokespecial #1 要调用到下面的Gender(java.lang.String, int, Gender$1)方法


若要研究完整的 Male 元素的初始化过程就得 javap -c Gender 看 Gender.java 产生的所有字节码,在此列出片断

image.png

在 static{} 中大致看下 Male 的初始过程:加载 Gender$1, 并调用它的 Gender$1(java.lang.String, int) 构造函数生成一个 Gender$1 实例赋给 Male 属性


既然enum是一个类,那么它就可以像一般的类一样拥有自己的属性与方法。但Java要求必须先定义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;  
        }  
    }

枚举实例的创建过程:枚举类型符合通用模式 Class Enum<E extends Enum>,而 E 表示枚举类型的名称。枚举类型的每一个值都将映射到 protected Enum(String name, int ordinal) 构造函数中,在这里,每个值的名称都被转换成一个字符串,并且序数设置表示了此设置被创建的顺序。

public enum Color{  
    RED, GREEN, BLUE, BLACK, PINK, WHITE;  
}

相当于调用了六次Enum构造方法


Enum(“RED”, 0);


Enum(“GREEN”, 1);


Enum(“BLUE”, 2);


Enum(“BLACK”, 3);


Enum(“PINK”,4);


Enum(“WHITE”, 5);


枚举类型的常用方法:


int compareTo(E o) 比较此枚举与指定对象的顺序。


Class getDeclaringClass() 返回与此枚举常量的枚举类型相对应的 Class 对象。


String name() 返回此枚举常量的名称,在其枚举声明中对其进行声明。


int ordinal() 返回枚举常量的序数(它在枚举声明中的位置,其中初始常量序数为零


String toString() 返回枚举常量的名称,它包含在声明中。


static <T extends Enum> T valueOf(Class enumType, String name) 返回带指定名称的指定枚举类型的枚举常量。


目录
相关文章
|
前端开发 JavaScript Java
【前端学java】Java中的接口和枚举概念(8)
【8月更文挑战第9天】Java中的接口和枚举概念(8)
149 4
|
安全 Java 测试技术
🎉Java零基础:全面解析枚举的强大功能
【10月更文挑战第19天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
434 60
|
Java
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
158 24
|
安全 Java 程序员
Java语言枚举(Enum)的深入探索
Java语言枚举(Enum)的深入探索
221 0
|
安全 Java 索引
Java——反射&枚举
本文介绍了Java反射机制及其应用,包括获取Class对象、构造方法、成员变量和成员方法。反射允许在运行时动态操作类和对象,例如创建对象、调用方法和访问字段。文章详细解释了不同方法的使用方式及其注意事项,并展示了如何通过反射获取类的各种信息。此外,还介绍了枚举类型的特点和使用方法,包括枚举的构造方法及其在反射中的特殊处理。
237 9
Java——反射&枚举
|
Java
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
209 5
|
安全 Java 开发者
Java 枚举(enum)详解
Java 中的枚举(`enum`)是一种特殊的数据类型,用于定义一组固定的常量,提升代码的类型安全性和可读性。枚举使用 `enum` 关键字定义,支持方法和构造函数,具有类型安全、单例、自动序列化等特点,并且可以遍历和用于 `switch` 语句中。实际应用包括状态机、指令集、类型标识等场景。枚举使代码更加清晰易维护。
1031 1
Java枚举使用的基本案例
这篇文章是关于Java枚举的基本使用,通过一个指令下发的代码案例,展示了如何定义枚举、使用枚举以及如何通过枚举实现指令的匹配和处理。
|
Java 开发者
在Java编程中,if-else与switch作为核心的条件控制语句,各有千秋。if-else基于条件分支,适用于复杂逻辑;而switch则擅长处理枚举或固定选项列表,提供简洁高效的解决方案
在Java编程中,if-else与switch作为核心的条件控制语句,各有千秋。if-else基于条件分支,适用于复杂逻辑;而switch则擅长处理枚举或固定选项列表,提供简洁高效的解决方案。本文通过技术综述及示例代码,剖析两者在性能上的差异。if-else具有短路特性,但条件增多时JVM会优化提升性能;switch则利用跳转表机制,在处理大量固定选项时表现出色。通过实验对比可见,switch在重复case值处理上通常更快。尽管如此,选择时还需兼顾代码的可读性和维护性。理解这些细节有助于开发者编写出既高效又优雅的Java代码。
219 2
|
安全 Java
Java进阶之枚举
【7月更文挑战第11天】Java枚举是Java 5引入的特性,用于定义固定常量集合,如星期。枚举是继承自`java.lang.Enum`的特殊类,编译后成为final类,每个枚举值是静态final实例。定义枚举用`enum`关键字,如`public enum Weekday {MONDAY, TUESDAY, ...}`。枚举可包含方法和变量,能实现接口但不能继承其他类。例如,`Weekday`枚举可实现`Describe`接口,提供`describe()`方法。在实际应用中,枚举常用于表示如响应状态等固定选项,便于类型安全和代码阅读。
126 8