tulip notes
首页
  • 学习笔记

    • 《Vue》
  • 踩坑日记

    • JavaScript
  • MQ
  • Nginx
  • IdentityServer
  • Redis
  • Linux
  • Java
  • SpringBoot
  • SpringCloud
  • MySql
  • docker
  • 算法与设计模式
  • 踩坑与提升
  • Git
  • GitHub技巧
  • Mac
  • 网络
  • 项目构建合集
  • 一些技巧
  • 面试
  • 一些杂货
  • 友情链接
  • 项目发布
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Star-Lord

希望一天成为大师的学徒
首页
  • 学习笔记

    • 《Vue》
  • 踩坑日记

    • JavaScript
  • MQ
  • Nginx
  • IdentityServer
  • Redis
  • Linux
  • Java
  • SpringBoot
  • SpringCloud
  • MySql
  • docker
  • 算法与设计模式
  • 踩坑与提升
  • Git
  • GitHub技巧
  • Mac
  • 网络
  • 项目构建合集
  • 一些技巧
  • 面试
  • 一些杂货
  • 友情链接
  • 项目发布
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Java基础与面向对象

    • Java中的一些概念
    • Java中的数组
    • String类跟关键字final
    • Java 日期时间与Date
    • Java中的异常处理
    • Java枚举
      • 什么是枚举
      • 枚举类的诞生
        • 枚举类的优势
      • 枚举类的定义
        • 简单的定义
        • 原理探究
        • 枚举类的内部结构
        • 带有构造函数和字段的枚举
        • 带有方法的枚举
    • Java序列化和反序列化
    • Java中的注解
    • Java中的IO流
    • Java中抽象类与接口
  • 高级进阶

  • 并发合集

  • JVM合集

  • 实战与细节

  • 代码之丑与提升

  • 《Java》学习笔记
  • Java基础与面向对象
EffectTang
2023-10-30
目录

Java枚举

# Java枚举

# 什么是枚举

枚举就是把对象或者属性值一个一个地列举出来。而枚举类就是起到把类属性值一个一个列举出来的作用,枚举类是java5中提出的新概念。

枚举类在 Java 中实际上是一个特殊的类。虽然 enum 关键字用于定义枚举类型,但枚举类本质上是一个继承自 java.lang.Enum 的类。

# 枚举类的诞生

在没有枚举类之前,开发者通常使用常量来表示一组固定的值,(至于为何使用static、final则为了属性值方便使用、和属性值不变)例如:

public class Color {
    public static final int RED = 1;
    public static final int GREEN = 2;
    public static final int BLUE = 3;
}
1
2
3
4
5

这种方法存在几个问题:

  • 类型不安全:这些常量的类型是 int,容易与其他 int 类型的变量混淆。
  • 容易出错:如果传入了一个不在预期范围内的 int 值,编译器无法检测到错误。

使用枚举类可以确保类型安全:

public enum Color {
    RED, GREEN, BLUE
}
1
2
3

现在,Color 是一个独立的类型,编译器会检查传递的值是否属于 Color 枚举类型。

以下是一个关于类型不安全的例子:

public class Color {
    public static final int RED = 1;
    public static final int GREEN = 2;
    public static final int BLUE = 3;
}


public class Main {
    public static void main(String[] args) {
        int color = 4; // 传入了一个非法值
        processColor(color);
    }

    public static void processColor(int color) {
        switch (color) {
            case Color.RED:
                System.out.println("Red");
                break;
            case Color.GREEN:
                System.out.println("Green");
                break;
            case Color.BLUE:
                System.out.println("Blue");
                break;
            default:
                System.out.println("Unknown color"); // 处理非法值
                break;
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

在这个例子中,color 变量被赋值为 4,这是一个非法值。编译器无法检测到这个错误,运行时会输出 "Unknown color"。

而使用枚举类则可以确保类型安全,因为枚举常量是类型安全的,编译器会检查传递的值是否属于枚举类型。

# 枚举类的优势

此外,枚举类还有以下几个优势:

  • 确保类型安全
  • 语义更清晰
  • 防止重复
  • 提供了更多功能

枚举类提供了更好的语义,使得代码更具可读性和可维护性。例如:

public void setTrafficLight(Color color) {
    // 处理交通灯的颜色
}

setTrafficLight(Color.RED); // 明确表示设置交通灯为红色
1
2
3
4
5

枚举类确保了常量的唯一性,避免了重复定义。例如,多个常量可能被定义为相同的值,导致混淆:

public class Status {
    public static final int ACTIVE = 1;
    public static final int INACTIVE = 1; // 错误:重复定义
}
1
2
3
4

使用枚举类可以避免这种情况:

public enum Status {
    ACTIVE, INACTIVE
}
1
2
3

枚举类不仅仅是常量的集合,还可以包含方法、字段和构造函数,从而提供更多的功能。例如:

public enum Color {
    RED("红色"), GREEN("绿色"), BLUE("蓝色");

    private String displayName;

    Color(String displayName) {
        this.displayName = displayName;
    }

    public String getDisplayName() {
        return displayName;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 枚举类的定义

在 Java 中,定义枚举类使用 enum 关键字。枚举类可以包含常量、方法、字段和构造函数,使其具备更多的功能。

# 简单的定义

最简单的枚举类只包含一组常量:

public enum DayOfWeek {
    MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
// 以下为 使用方法
DayOfWeek today = DayOfWeek.FRIDAY;
// 直接  类名.常量名 即可
1
2
3
4
5
6

注意:枚举类的常量(MONDAY这些)不是 String 类型,而是枚举类型本身。具体来说,DayOfWeek 枚举类中的 MONDAY、TUESDAY 等常量的类型是 DayOfWeek。

# 原理探究

看到使用方法,是否想到了static关键字,没错。它的内部实现确实使用了static。

在 Java 中,枚举类本质上是一个特殊的类,每个枚举常量都是这个类的一个实例。这些实例在编译时创建,并且是唯一的、不可变的。

public enum DayOfWeek {
    MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
1
2
3

在这个例子中,MONDAY、TUESDAY、WEDNESDAY、THURSDAY、FRIDAY、SATURDAY 和 SUNDAY 都是 DayOfWeek 类的实例。这些实例在编译时创建,并且在整个应用程序的生命周期中是唯一的。

# 枚举类的内部结构

为了更好地理解这一点,可以看看枚举类的内部结构。编译器会将枚举类编译成类似于以下的类:

public final class DayOfWeek extends Enum<DayOfWeek> {
    public static final DayOfWeek MONDAY = new DayOfWeek("MONDAY", 0);
    public static final DayOfWeek TUESDAY = new DayOfWeek("TUESDAY", 1);
    public static final DayOfWeek WEDNESDAY = new DayOfWeek("WEDNESDAY", 2);
    public static final DayOfWeek THURSDAY = new DayOfWeek("THURSDAY", 3);
    public static final DayOfWeek FRIDAY = new DayOfWeek("FRIDAY", 4);
    public static final DayOfWeek SATURDAY = new DayOfWeek("SATURDAY", 5);
    public static final DayOfWeek SUNDAY = new DayOfWeek("SUNDAY", 6);

    private DayOfWeek(String name, int ordinal) {
        super(name, ordinal);
    }

    public static DayOfWeek[] values() {
        return (DayOfWeek[]) $VALUES.clone();
    }

    public static DayOfWeek valueOf(String name) {
        return (DayOfWeek) Enum.valueOf(DayOfWeek.class, name);
    }

    private static final DayOfWeek[] $VALUES = new DayOfWeek[] {
        MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
    };
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
  1. 构造函数:每个枚举常量都是通过调用枚举类的私有构造函数创建的。构造函数接受两个参数:name 和 ordinal,分别表示枚举常量的名称和序号。
  2. 唯一性:每个枚举常量在编译时创建,并且是唯一的。这些实例在运行时不会被重新创建。
  3. 不可变性:枚举常量是不可变的,一旦创建,它们的值不能被修改。
  4. 类型安全:枚举常量的类型是枚举类本身,确保了类型安全。

好了下面让我们继续介绍它的定义方式。

# 带有构造函数和字段的枚举

枚举类可以包含构造函数和字段,用于存储额外的信息:

public enum Color {
    RED("红色"),
    GREEN("绿色"),
    BLUE("蓝色");

    private String displayName;

    // 构造函数
    Color(String displayName) {
        this.displayName = displayName;
    }

    // 获取显示名称的方法
    public String getDisplayName() {
        return displayName;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 带有方法的枚举

枚举类可以包含方法,提供更多的功能:

public enum Planet {
    MERCURY(3.303e+23, 2.4397e6),
    VENUS(4.869e+24, 6.0518e6),
    EARTH(5.976e+24, 6.37814e6),
    MARS(6.421e+23, 3.3972e6),
    JUPITER(1.9e+27, 7.1492e7),
    SATURN(5.688e+26, 6.0268e7),
    URANUS(8.686e+25, 2.5559e7),
    NEPTUNE(1.024e+26, 2.4746e7);

    private final double mass;   // in kilograms
    private final double radius; // in meters

    // 构造函数
    Planet(double mass, double radius) {
        this.mass = mass;
        this.radius = radius;
    }

    // 获取质量的方法
    public double getMass() {
        return mass;
    }

    // 获取半径的方法
    public double getRadius() {
        return radius;
    }

    // 计算重力加速度的方法
    public double surfaceGravity() {
        if (radius == 0) {
            throw new IllegalStateException("Radius cannot be zero");
        }
        return G * mass / (radius * radius);
    }

    // 计算表面重量的方法
    public double surfaceWeight(double otherMass) {
        return otherMass * surfaceGravity();
    }

    // 引力常数
    private static final double G = 6.67300E-11;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
上次更新: 2025/04/23, 16:23:16
Java中的异常处理
Java序列化和反序列化

← Java中的异常处理 Java序列化和反序列化→

最近更新
01
面向切面跟自定义注解的结合
05-22
02
时间跟其他数据的序列化
05-19
03
数据加密与安全
05-17
更多文章>
Theme by Vdoing | Copyright © 2023-2025 EffectTang
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式