学习总结录 学习总结录
首页
归档
分类
标签
  • Java基础
  • Java集合
  • MySQL
  • Redis
  • JVM
  • 多线程
  • 计算机网络
  • 操作系统
  • Spring
  • Kafka
  • Elasticsearch
  • Python
  • 面试专题
  • 案例实践
  • 工具使用
  • 项目搭建
  • 服务治理
  • ORM框架
  • 分布式组件
  • MiniSpring
  • 设计模式
  • 算法思想
  • 编码规范
友链
关于
GitHub (opens new window)
首页
归档
分类
标签
  • Java基础
  • Java集合
  • MySQL
  • Redis
  • JVM
  • 多线程
  • 计算机网络
  • 操作系统
  • Spring
  • Kafka
  • Elasticsearch
  • Python
  • 面试专题
  • 案例实践
  • 工具使用
  • 项目搭建
  • 服务治理
  • ORM框架
  • 分布式组件
  • MiniSpring
  • 设计模式
  • 算法思想
  • 编码规范
友链
关于
GitHub (opens new window)
  • Java基础

    • Java-枚举
      • 一、枚举简介
      • 二、枚举的本质
      • 三、枚举的方法
      • 四、枚举的特性
        • 添加方法
        • 实现接口
        • 枚举不可以继承
      • 五、枚举的应用
        • 组织常量
        • switch状态机
        • 状态码
        • 组织枚举
        • 策略枚举
      • 六、枚举工具类
        • EnumSet
        • EnumMap
      • 参考
    • Java-反射
    • Java-泛型
    • Java-异常
    • Java-注解
  • Java集合

  • MySQL

  • Redis

  • JVM

  • 多线程

  • 计算机网络

  • Spring

  • Kafka

  • Elasticsearch

  • Python

  • 面试专题

  • 知识库
  • Java基础
旭日
2023-03-31
目录

Java-枚举

# 一、枚举简介

enum 的全称为 enumeration, 是 JDK5 中引入的特性。在 Java 中,被 enum 关键字修饰的类型就是枚举类型。

public enum ResultCode {

    /**
     * 操作成功
     */
    SUCCESS(200, "操作成功"),

    /**
     * 操作失败
     */
    FAILED(500, "操作失败"),

    /**
     * 编码
     */
    final Integer code;

    /**
     * 消息
     */
    final String message;

    ResultCode(Integer code, String message) {
        this.code = code;
        this.message = message;
    }
}

枚举的好处:可以将常量组织起来,统一进行管理

枚举的典型应用场景:状态码、错误码

# 二、枚举的本质

java.lang.Enum类声明如下:

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

我们通过javap命令来执行一个字节码文件输出如下:

Compiled from "LoginCodeEnum.java"
public final class com.xu.wxxplatformserver.common.LoginCodeEnum extends java.lang.Enum<com.xu.wxxplatformserver.common.LoginCodeEnum> {
  public static final com.xu.wxxplatformserver.common.LoginCodeEnum arithmetic;
  public static final com.xu.wxxplatformserver.common.LoginCodeEnum chinese;
  public static final com.xu.wxxplatformserver.common.LoginCodeEnum chinese_gif;
  public static final com.xu.wxxplatformserver.common.LoginCodeEnum gif;
  public static final com.xu.wxxplatformserver.common.LoginCodeEnum spec;
  public static com.xu.wxxplatformserver.common.LoginCodeEnum[] values();
  public static com.xu.wxxplatformserver.common.LoginCodeEnum valueOf(java.lang.String);
  static {};
}

从输出的信息可以看到尽管我们定义的为enum,但是实际上,enum的本质是java.lang.Enum 的子类。enum 是一种受限制的类,并且具有自己的方法。枚举这种特殊的类因为被修饰为 final,所以不能继承其他类。定义的枚举值,会被默认修饰为 public static final ,从修饰关键字,即可看出枚举值本质上是静态常量。

# 三、枚举的方法

在 enum 中,提供了一些基本方法:

  • values():返回 enum 实例的数组,而且该数组中的元素严格保持在 enum 中声明时的顺序。
  • name():返回实例名。
  • ordinal():返回实例声明时的次序,从 0 开始。
  • getDeclaringClass():返回实例所属的 enum 类型。
  • equals() :判断是否为同一个对象。

基本方法展示:

public class EnumMethodDemo {
    enum Color {RED, GREEN, BLUE;}
    enum Size {BIG, MIDDLE, SMALL;}
    public static void main(String[] args) {
        System.out.println("=========== Print all Color ===========");
        for (Color c : Color.values()) {
            System.out.println(c + " ordinal: " + c.ordinal());
        }
        System.out.println("=========== Print all Size ===========");
        for (Size s : Size.values()) {
            System.out.println(s + " ordinal: " + s.ordinal());
        }
        Color green = Color.GREEN;
        System.out.println("green name(): " + green.name());
        System.out.println("green getDeclaringClass(): " + green.getDeclaringClass());
        System.out.println("green hashCode(): " + green.hashCode());
        System.out.println("green compareTo Color.GREEN: " + green.compareTo(Color.GREEN));
        System.out.println("green equals Color.GREEN: " + green.equals(Color.GREEN));
        System.out.println("green equals Size.MIDDLE: " + green.equals(Size.MIDDLE));
        System.out.println("green equals 1: " + green.equals(1));
        System.out.format("green == Color.BLUE: %b\n", green == Color.BLUE);
    }
}

输出:

=========== Print all Color ===========
RED ordinal: 0
GREEN ordinal: 1
BLUE ordinal: 2
=========== Print all Size ===========
BIG ordinal: 0
MIDDLE ordinal: 1
SMALL ordinal: 2
green name(): GREEN
green getDeclaringClass(): class me.xu.EnumMethodDemo$Color
green hashCode(): 460141958
green compareTo Color.GREEN: 0
green equals Color.GREEN: true
green equals Size.MIDDLE: false
green equals 1: false
green == Color.BLUE: false

Process finished with exit code 0

# 四、枚举的特性

枚举除了不能继承,基本上可以将enum看做一个常规的类。枚举值默认为从 0 开始的有序数值 。那么问题来了:如何为枚举显式的赋值。

# 添加方法

通过为enum添加方法来间接实现显式赋值。

public enum ResultCode {

    /**
     * 操作成功
     */
    SUCCESS(200, "操作成功"),

    /**
     * 操作失败
     */
    FAILED(500, "操作失败"),

    /**
     * 编码
     */
    final Integer code;

    /**
     * 消息
     */
    final String message;

    ResultCode(Integer code, String message) {
        this.code = code;
        this.message = message;
    }
}

# 实现接口

enum可以和一般类一样去实现接口。

public interface INumberEnum {
    int getCode();
    String getDescription();
}

public enum ErrorCodeEn2 implements INumberEnum {
    OK(0, "成功"),
    ERROR_A(100, "错误A"),
    ERROR_B(200, "错误B");

    ErrorCodeEn2(int number, String description) {
        this.code = number;
        this.description = description;
    }

    private int code;
    private String description;

    @Override
    public int getCode() {
        return code;
    }

    @Override
    public String getDescription() {
        return description;
    }
}

# 枚举不可以继承

由于enum已经作为子类继承了Enum,而且Java 不支持多重继承,所以 enum 不能再继承其他类,当然也不能继承另一个 enum。

# 五、枚举的应用

# 组织常量

在 JDK5 之前,在 Java 中定义常量都是public static final TYPE A; 这样的形式。有了枚举,你可以将有关联关系的常量组织起来,使代码更加易读、安全,并且还可以使用枚举提供的方法。

enum Color { RED, GREEN, BLUE }

# switch状态机

我们经常使用 switch 语句来写状态机。JDK7 以后,switch 已经支持 int、char、String、enum 类型的参数。这几种类型的参数比较起来,使用枚举的 switch 代码更具有可读性。

public class StateMachineDemo {
    public enum Signal {
        GREEN, YELLOW, RED
    }

    public static String getTrafficInstruct(Signal signal) {
        String instruct = "信号灯故障";
        switch (signal) {
            case RED:
                instruct = "红灯停";
                break;
            case YELLOW:
                instruct = "黄灯请注意";
                break;
            case GREEN:
                instruct = "绿灯行";
                break;
            default:
                break;
        }
        return instruct;
    }

    public static void main(String[] args) {
        System.out.println(getTrafficInstruct(Signal.RED));
    }
}
// Output:
// 红灯停

# 状态码

枚举常被用于定义程序错误码。下面是一个简单示例:

@Getter
public enum ResultCode {

    /**
     * 操作成功
     */
    SUCCESS(200, "操作成功"),

    /**
     * 操作失败
     */
    FAILED(500, "操作失败"),

    /**
     * 编码
     */
    final Integer code;

    /**
     * 消息
     */
    final String message;

    ResultCode(Integer code, String message) {
        this.code = code;
        this.message = message;
    }
}

# 组织枚举

可以将类型相近的枚举通过接口或类组织起来,通常采用接口方式来组织。由于Java 接口在编译时会自动为 enum 类型加上public static修饰符;Java 类在编译时会自动为 enum 类型加上 static 修饰符。通过接口防止组织的枚举是可以在任何地方进行访问的。

public class EnumInInterfaceDemo {
    public interface INumberEnum {
        int getCode();
        String getDescription();
    }


    public interface Plant {
        enum Vegetable implements INumberEnum {
            POTATO(0, "土豆"),
            TOMATO(0, "西红柿");

            Vegetable(int number, String description) {
                this.code = number;
                this.description = description;
            }

            private int code;
            private String description;

            @Override
            public int getCode() {
                return this.code;
            }

            @Override
            public String getDescription() {
                return this.description;
            }
        }


        enum Fruit implements INumberEnum {
            APPLE(0, "苹果"),
            ORANGE(0, "桔子"),
            BANANA(0, "香蕉");

            Fruit(int number, String description) {
                this.code = number;
                this.description = description;
            }

            private int code;
            private String description;

            @Override
            public int getCode() {
                return this.code;
            }

            @Override
            public String getDescription() {
                return this.description;
            }
        }
    }

    public static void main(String[] args) {
        for (Plant.Fruit f : Plant.Fruit.values()) {
            System.out.println(f.getDescription());
        }
    }
}
// Output:
// 苹果
// 桔子
// 香蕉

# 策略枚举

枚举通过枚举嵌套枚举的方式,将枚举常量分类处理。这种做法虽然没有 switch 语句简洁,但是更加安全、灵活。

enum PayrollDay {
    MONDAY(PayType.WEEKDAY), TUESDAY(PayType.WEEKDAY), WEDNESDAY(
            PayType.WEEKDAY), THURSDAY(PayType.WEEKDAY), FRIDAY(PayType.WEEKDAY), SATURDAY(
            PayType.WEEKEND), SUNDAY(PayType.WEEKEND);

    private final PayType payType;

    PayrollDay(PayType payType) {
        this.payType = payType;
    }

    double pay(double hoursWorked, double payRate) {
        return payType.pay(hoursWorked, payRate);
    }

    // 策略枚举
    private enum PayType {
        WEEKDAY {
            double overtimePay(double hours, double payRate) {
                return hours <= HOURS_PER_SHIFT ? 0 : (hours - HOURS_PER_SHIFT)
                        * payRate / 2;
            }
        },
        WEEKEND {
            double overtimePay(double hours, double payRate) {
                return hours * payRate / 2;
            }
        };
        private static final int HOURS_PER_SHIFT = 8;

        abstract double overtimePay(double hrs, double payRate);

        double pay(double hoursWorked, double payRate) {
            double basePay = hoursWorked * payRate;
            return basePay + overtimePay(hoursWorked, payRate);
        }
    }
}

# 六、枚举工具类

# EnumSet

EnumSet 是枚举类型的高性能 Set 实现。它要求放入它的枚举常量必须属于同一枚举类型。

主要接口:

  • noneOf - 创建一个具有指定元素类型的空 EnumSet
  • allOf - 创建一个指定元素类型并包含所有枚举值的 EnumSet
  • range - 创建一个包括枚举值中指定范围元素的 EnumSet
  • complementOf - 初始集合包括指定集合的补集
  • of - 创建一个包括参数中所有元素的 EnumSet
  • copyOf - 创建一个包含参数容器中的所有元素的 EnumSet
public class EnumMethodDemo {
    enum Color {RED, GREEN, BLUE;}
    enum Size {BIG, MIDDLE, SMALL;}
    public static void main(String[] args) {
        System.out.println("EnumSet展示");
        EnumSet<Size> sizeSet = EnumSet.allOf(Size.class);
        for (Size e : sizeSet) {
            System.out.println(e.name() + " : " + e.ordinal());
        }
    }
}

# EnumMap

EnumMap 是专门为枚举类型量身定做的 Map 实现。它只能接收同一枚举类型的实例作为键值,并且由于枚举类型实例的数量相对固定并且有限,所以 EnumMap 使用数组来存放与枚举类型对应的值。这使得 EnumMap 的效率非常高。

主要接口:

  • size - 返回键值对数
  • containsValue - 是否存在指定的 value
  • containsKey - 是否存在指定的 key
  • get - 根据指定 key 获取 value
  • put - 取出指定的键值对
  • remove - 删除指定 key
  • putAll - 批量取出键值对
  • clear - 清除数据
  • keySet - 获取 key 集合
  • values - 返回所有
public class EnumMapDemo {
    public enum Signal {
        GREEN, YELLOW, RED
    }

    public static void main(String[] args) {
        System.out.println("EnumMap展示");
        EnumMap<Signal, String> errMap = new EnumMap(Signal.class);
        errMap.put(Signal.RED, "红灯");
        errMap.put(Signal.YELLOW, "黄灯");
        errMap.put(Signal.GREEN, "绿灯");
        for (Iterator<Map.Entry<Signal, String>> iter = errMap.entrySet().iterator(); iter.hasNext();) {
            Map.Entry<Signal, String> entry = iter.next();
            System.out.println(entry.getKey().name() + " : " + entry.getValue());
        }
    }
}

# 参考

深入理解 Java 枚举 (opens new window)

#Java
上次更新: 2024/06/29, 15:13:44
Java-反射

Java-反射→

最近更新
01
基础概念
10-31
02
Pytorch
10-30
03
Numpy
10-30
更多文章>
Theme by Vdoing | Copyright © 2021-2024 旭日 | 蜀ICP备2021000788号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式