Java枚举类型

枚举类型定义

  1. 简单枚举

    public enum Day0 {
        MONDAY,
        TUESDAY,
        WEDNESDAY,
        THURSDAY,
        FRIDAY,
        SATURDAY,
        SUNDAY;
    }
    复制代码
  2. 向枚举中自定义属性和方法

    (1) 自定义了一个day属性

    @Getter
    public enum Day1 {
        MONDAY("Monday"),
        TUESDAY("Tuesday"),
        WEDNESDAY("Wednesday"),
        THURSDAY("Thursday"),
        FRIDAY("Friday"),
        SATURDAY("Saturday"),
        SUNDAY("Sunday");
    
        private String day;
        Day1(String day) {
            this.day = day;
        }
    }
    复制代码

    (2) 自定义了2个属性

    @Getter
    public enum Day {
        MONDAY(0, "Monday"),
        TUESDAY(1, "Tuesday"),
        WEDNESDAY(2, "Wednesday"),
        THURSDAY(3, "Thursday"),
        FRIDAY(4, "Friday"),
        SATURDAY(5, "Saturday"),
        SUNDAY(6, "Sunday");
        
        private int val;
        private String day;
        Day(int val, String day) { // 枚举类型构造函数必为private的,不需指定
            this.val = val;
            this.day = day;
        }
    }
    复制代码

枚举类型实现原理

在使用关键字enum创建枚举类型并编译后,编译器会为我们生成一个相关的类,这个类继承了java.lang.Enum类。

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

    // 枚举的常量名,例如MONDAY, TUESDAY
    private final String name;

    public final String name() {
        return name;
    }

    // 枚举的序号,按顺序从0开始
    private final int ordinal;

    public final int ordinal() {
        return ordinal;
    }

    protected Enum(String name, int ordinal) {
        this.name = name;
        this.ordinal = ordinal;
    }

    public String toString() {
        return name;
    }
    
    public static <T extends Enum<T>> T valueOf(Class<T> enumType,
                                                String name) {
        T result = enumType.enumConstantDirectory().get(name);
        if (result != null)
            return result;
        if (name == null)
            throw new NullPointerException("Name is null");
        throw new IllegalArgumentException(
            "No enum constant " + enumType.getCanonicalName() + "." + name);
    }
    ...
}
复制代码

javap反编译枚举类型Day:

public final class com.tplink.test.pojo.Day extends java.lang.Enum<com.tplink.test.pojo.Day> {
  public static final com.tplink.test.pojo.Day MONDAY;
  public static final com.tplink.test.pojo.Day TUESDAY;
  public static final com.tplink.test.pojo.Day WEDNESDAY;
  public static final com.tplink.test.pojo.Day THURSDAY;
  public static final com.tplink.test.pojo.Day FRIDAY;
  public static final com.tplink.test.pojo.Day SATURDAY;
  public static final com.tplink.test.pojo.Day SUNDAY;
  public static com.tplink.test.pojo.Day[] values(); // 编译器添加的方法
  public static com.tplink.test.pojo.Day valueOf(java.lang.String); // 编译器添加的方法,根据名字查找对象
  public int getVal(); // 自定义getter
  public java.lang.String getDay(); // 自定义getter
  static {};
}
复制代码

默认的转换

默认的枚举类型转换只能传枚举类型的ordinal和name。

例如:

// restcontroller
@PostMapping("/day1")
public void day1(@RequestBody XxVo vo) {
    ...
}

// VO
@Data
public class XxVo {
    private Day1 day1; // day1是上文定义的枚举类
}
复制代码

可以接收:

// ordinal
{
	"day1": 0
}
// name
{
    "day1": "MONDAY"
}
复制代码

不能接收:

{
    "day1": "Monday"
}
复制代码

下面介绍自定义转换方法。

RequestBody中的枚举类型转换

RequestBody的解析依赖于HttpMessageConverter。

使用Jackson的@JsonValue@JsonCreator注解。

@Getter
public enum Day {
    MONDAY(1, "monday"),
    TUESDAY(2, "tuesday"),
    WEDNESDAY(3, "wednesday"),
    THURSDAY(4, "thursday"),
    FRIDAY(5, "friday"),
    SATURDAY(6, "saturday"),
    SUNDAY(-1, "sunday");

    private Integer value;
    private String day;

    Day(int value, String day) {
        this.value = value;
        this.day = day;
    }

    @JsonValue
    public Integer getValue() {
        return this.value;
    }

    @JsonCreator
    public static Day Day(Integer value) {
        for (Day day : values()) {
            if (day.value.equals(value)) {
                return day;
            }
        }

        return null;
    }
}
复制代码

RequestParam中的枚举类型转换

RequestParam中的参数转换依赖于WebDataBinder机制。

定义一个BaseEnum接口,自定义Converter并注册进WebMvcConfigurer。

public interface BaseEnum {

    /**
     * 序列化
     * @return
     */
    Object toValue();

    /**
     * 反序列化
     * @param enumType 实际枚举类型
     * @param value 当前值
     * @param <T> 枚举类型并实现当前接口
     * @return 枚举常量
     */
    static <T extends Enum<T> & BaseEnum> T valueOf(Class<T> enumType, Object value) {
        if (enumType == null || value == null) {
            return null;
        }

        T[] enumConstants = enumType.getEnumConstants();
        for (T enumConstant : enumConstants) {
            Object enumValue = enumConstant.toValue();
            if (Objects.equals(enumValue, value)
                    || Objects.equals(enumValue.toString(), value.toString())) {
                return enumConstant;
            }
        }

        return null;
    }
}
复制代码
@SuppressWarnings({"unchecked", "rawtypes"})
public class StringToEnumConverterFactory implements ConverterFactory<String, BaseEnum> {

    @Override
    public <T extends BaseEnum> Converter<String, T> getConverter(Class<T> targetType) {
        return new StringToEnum(targetType);
    }

    private class StringToEnum<T extends Enum<T> & BaseEnum> implements Converter<String, T> {

        private final Class<T> enumType;

        public StringToEnum(Class<T> enumType) {
            this.enumType = enumType;
        }

        @Override
        public T convert(String source) {
            if (source.isEmpty()) {
                return null;
            }
            return (T) BaseEnum.valueOf(this.enumType, source.trim());
        }
    }
}
复制代码
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverterFactory(new StringToEnumConverterFactory());
    }
}
复制代码

枚举类型序列化

使用Jackson的@JsonFormat注解,不能和@JsonValue同时使用。

@Getter
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum Day {
    MONDAY(0, "monday"),
    TUESDAY(1, "tuesday"),
    WEDNESDAY(2, "wednesday"),
    THURSDAY(3, "thursday"),
    FRIDAY(4, "friday"),
    SATURDAY(5, "saturday"),
    SUNDAY(6, "sunday");

    private int val;
    private String day;
    Day(int val, String day) {
        this.val = val;
        this.day = day;
    }
}
复制代码

则可序列化如下的形式:

{
    "val": 0,
    "day": "monday"
}
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享