Java反射之枚举类型

500 阅读2分钟

这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战

Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。

对于对象、成员变量、方法相关的反射实现,大家应该比较熟悉了。今天,我们聊聊与枚举相关的反射内容。

枚举简介

枚举enum为java 5版本新增的一种特性。其使用起来非常简单:

  1. 定义枚举
public enum PayStatus {
    WAITING_PAY(1, "待支付"),
    FINISH_PAY(2, "支付完成"),
    RETURN(3, "已退回"),
    ;

    private Integer code;
    private String msg;

    PayStatus(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }
}
  1. 直接使用PayStatus.WAITING_PAY即可表示一种状态
public class Order {
    private PayStatus payStatus;
    
    public static void main(String[] args) {
        Order order = new Order();
        order.setPayStatus(PayStatus.FINISH_PAY);
    }

    public PayStatus getPayStatus() {
        return payStatus;
    }

    public void setPayStatus(PayStatus payStatus) {
        this.payStatus = payStatus;
    }
}

java.lang.Enum 类

在Java世界中,万物皆是对象。那枚举又是什么类「对象」呢?当然它肯定是Object类对象。除此之外,它还是java.lang.Enum类的对象。

官方文档的描述

* 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
* <cite>The Java&trade; Language Specification</cite>.
* @since   1.5
public abstract class Enum<E extends Enum<E>>
        implements Comparable<E>, Serializable {
...
}
// 中文大意:
这是所有 Java 语言枚举类型的公共基类。 有关枚举的更多信息,包括对编译器合成的隐式声明方法的描述,可以在Java™ 语言规范的第 8.9 节中找到

示例代码

public static void main(String[] args) {
    System.out.println(PayStatus.class.getSuperclass());
    System.out.println(PayStatus.FINISH_PAY.getClass().getSuperclass());
}
// 控制台输出:
class java.lang.Enum
class java.lang.Enum

从文档描述和示例代码可以看出,所有的枚举类都是继承java.lang.Enum类,只是这个继承不需要我们在代码显式定义出来。这就好比所有类默认继承Object,而不需要我们手动书写继承Object类。

Enum类也很简单,它只有两个属性:

  • name 枚举的名称

  • ordinal 枚举的顺序

这两个属性都被final修饰,这两个值在定义枚举的时候就确定了,如WAITING_PAY(1, "待支付")就已经确定其name为「WAITING_PAY」,ordinal为0。

其中name在toString方法有用到。

public String toString() {
    return name;
}

所以我们平时在控制台看到枚举值(toString)就是我们定义枚举的名称.

枚举相关的反射

与枚举相关的反射方法只有一个:Class类中getEnumConstants()方法,可以获取枚举类下的所有枚举值。

用法示例:

public class EnumUtil {
    static Map<String, Class> enumMap= new HashMap<>();
    static {
        enumMap.put("payStatus", PayStatus.class);
        enumMap.put("payType", PayType.class);
    }

    public static List<String> getEnumsByType(String type) {
        List<String> list = new ArrayList<>();
        Class enumClass = enumMap.get(type);
        // 获取所有枚举值
        Object[] enumConstants = enumClass.getEnumConstants();
        for (Object obj : enumConstants) {
            list.add(String.valueOf(obj));
        }
        return list;
    }

    public static void main(String[] args) {
        List<String> payStatus = getEnumsByType("payStatus");
        System.out.println(payStatus);
    }
}
// 控制台输出结果:
[WAITING_PAY, FINISH_PAY, RETURN]

因为枚举本身就很简单,所以通过反射动态获取枚举值的场景很少。前后端交互场景,可以通过枚举的反射机制实现数值与枚举的对应。