美文网首页
动态创建枚举类型

动态创建枚举类型

作者: Yluozi | 来源:发表于2021-05-11 10:45 被阅读0次

枚举类型是Java 5中新增特性的一部分,它是一种特殊的数据类型,之所以特殊是因为它既是一种类(class)类型却又比类类型多了些特殊的约束,但是这些约束的存在也造就了枚举类型的简洁性、安全性以及便捷性。

//定义枚举类型

public class EnumDemo {

    public static void main(String[] args){
        //直接引用
        Day day =Day.MONDAY;
    }

}
//定义枚举类型
enum Day {
    MONDAY, TUESDAY, WEDNESDAY,
    THURSDAY, FRIDAY, SATURDAY, SUNDAY
}

动态定义枚举类型

调用的工具程序如下:

package net.cnki.urtp.utils;
import sun.reflect.ConstructorAccessor;
import sun.reflect.FieldAccessor;
import sun.reflect.ReflectionFactory;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class DynamicEnumUtil {

    private static ReflectionFactory reflectionFactory = ReflectionFactory.getReflectionFactory();

    private static void setFailsafeFieldValue(Field field, Object target, Object value) throws NoSuchFieldException,
            IllegalAccessException {

        // let's make the field accessible
        field.setAccessible(true);

        // next we change the modifier in the Field instance to
        // not be final anymore, thus tricking reflection into
        // letting us modify the static final field
        Field modifiersField = Field.class.getDeclaredField("modifiers");
        modifiersField.setAccessible(true);
        int modifiers = modifiersField.getInt(field);

        // blank out the final bit in the modifiers int
        modifiers &= ~Modifier.FINAL;
        modifiersField.setInt(field, modifiers);

        FieldAccessor fa = reflectionFactory.newFieldAccessor(field, false);
        fa.set(target, value);
    }

    private static void blankField(Class<?> enumClass, String fieldName) throws NoSuchFieldException,
            IllegalAccessException {
        for (Field field : Class.class.getDeclaredFields()) {
            if (field.getName().contains(fieldName)) {
                AccessibleObject.setAccessible(new Field[] { field }, true);
                setFailsafeFieldValue(field, enumClass, null);
                break;
            }
        }
    }

    private static void cleanEnumCache(Class<?> enumClass) throws NoSuchFieldException, IllegalAccessException {
        blankField(enumClass, "enumConstantDirectory"); // Sun (Oracle?!?) JDK 1.5/6
        blankField(enumClass, "enumConstants"); // IBM JDK
    }

    private static ConstructorAccessor getConstructorAccessor(Class<?> enumClass, Class<?>[] additionalParameterTypes)
            throws NoSuchMethodException {
        Class<?>[] parameterTypes = new Class[additionalParameterTypes.length + 2];
        parameterTypes[0] = String.class;
        parameterTypes[1] = int.class;
        System.arraycopy(additionalParameterTypes, 0, parameterTypes, 2, additionalParameterTypes.length);
        return reflectionFactory.newConstructorAccessor(enumClass.getDeclaredConstructor(parameterTypes));
    }

    private static Object makeEnum(Class<?> enumClass, String value, int ordinal, Class<?>[] additionalTypes,
                                   Object[] additionalValues) throws Exception {
        Object[] parms = new Object[additionalValues.length + 2];
        parms[0] = value;
        parms[1] = Integer.valueOf(ordinal);
        System.arraycopy(additionalValues, 0, parms, 2, additionalValues.length);
//       parms[1] = parms[parms.length-1];
        return enumClass.cast(getConstructorAccessor(enumClass, additionalTypes).newInstance(parms));
    }

    /**
     * Add an enum instance to the enum class given as argument
     *
     * @param <T> the type of the enum (implicit)
     * @param enumType the class of the enum to be modified
     * @param enumName the name of the new enum instance to be added to the class.
     */
    @SuppressWarnings("unchecked")
    public static <T extends Enum<?>> T addEnum(Class<T> enumType, String enumName, Class<?>[] additionalTypes, Object[] additionalValues) {

        // 0. Sanity checks
        if (!Enum.class.isAssignableFrom(enumType)) {
            throw new RuntimeException("class " + enumType + " is not an instance of Enum");
        }

        // 1. Lookup "$VALUES" holder in enum class and get previous enum instances
        Field valuesField = null;
        Field[] fields = enumType.getDeclaredFields();
        for (Field field : fields) {
            if (field.getName().contains("$VALUES")) {
                valuesField = field;
                break;
            }
        }
        if(valuesField == null ){
            return null;
        }
        AccessibleObject.setAccessible(new Field[] { valuesField }, true);

        try {

            // 2. Copy it
            T[] previousValues = (T[]) valuesField.get(enumType);
            List<T> values = new ArrayList<T>(Arrays.asList(previousValues));

            // 3. build new enum
            T newValue = (T) makeEnum(enumType, enumName, values.size(), additionalTypes, additionalValues);

            // 4. add new value
            values.add(newValue);

            // 5. Set new values field
            setFailsafeFieldValue(valuesField, null, values.toArray((T[]) Array.newInstance(enumType, 0)));

            // 6. Clean enum cache
            cleanEnumCache(enumType);
            return newValue;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage(), e);
        }
    }


    public static void main(String[] args) {

    }

}

动态创建处代码:

package net.cnki.urtp.service.common;

import net.cnki.urtp.domain.model.ResourceType;
import net.cnki.urtp.service.ProductConfigService;
import net.cnki.urtp.utils.DynamicEnumUtil;
import net.cnki.urtp.utils.ResourceUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.List;

/**
 * @author :
 * @description:枚举动态获取
 * @date :Created in 2021/3/2 17:04 *
 * @modified By:
 */

@Component
public class SetEnumUtils {

    @Autowired
    ProductConfigService productConfigService;

    @PostConstruct
    public void setConfigure() {

        try {
            //遍历set所有资源的ID、代码、名称及封面信息(要求代码、ID必须不能为空;另外值如果为空,则赋值空字符串,避免无效定义)
            List<ResourceType> list = productConfigService.getResourceTypeAll();
            for(ResourceType it: list) {
                if (ObjectUtils.allNotNull(it,it.getResourceId(),it.getResourceName()) && it.getResourceId() > 0 && StringUtils.isNotBlank(it.getResourceCode())) {
                    //动态加载枚举配置
                    DynamicEnumUtil.addEnum(ResourceUtils.ResourceID.class,it.getResourceCode(),new Class[]{String.class},new Object[]{it.getResourceId().toString()});
                    DynamicEnumUtil.addEnum(ResourceUtils.ResourceCode.class,it.getResourceCode(),new Class[]{String.class},new Object[]{it.getResourceCode()});
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

通过java反射机制动态创建枚举类型,
addEnum(Class<T> enumType, String enumName, Class<?>[] additionalTypes, Object[] additionalValues)

DynamicEnumUtil.addEnum(ResourceUtils.ResourceID.class,it.getResourceCode(),new Class[]{String.class},new Object[]{it.getResourceId().toString()})

注意:本人在加载项目前调用此方法,使用@PostConstruct注解

@Component (把普通pojo实例化到spring容器中,相当于配置文件中的 )
@Controller 控制器(注入服务)
用于标注控制层,相当于struts中的action层
@Service 服务(注入dao)
用于标注服务层,主要用来进行业务的逻辑处理
@Repository(实现dao访问)
用于标注数据访问层,也可以说用于标注数据访问组件,即DAO组件

泛指各种组件,就是说当我们的类不属于各种归类的时候(不属于@Controller、@Services等的时候),我们就可以使用@Component来标注这个类。

@PostConstruct注解好多人以为是Spring提供的。其实是Java自己的注解。
Java中该注解的说明:@PostConstruct该注解被用来修饰一个非静态的void()方法。被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次。PostConstruct在构造函数之后执行,init()方法之前执行。

通常我们会是在Spring框架中使用到@PostConstruct注解 该注解的方法在整个Bean初始化中的执行顺序:
Constructor(构造方法) -> @Autowired(依赖注入) -> @PostConstruct(注释的方法)
应用:在静态方法中调用依赖注入的Bean中的方法。

相关文章

  • 动态创建枚举类型

    枚举类型是Java 5中新增特性的一部分,它是一种特殊的数据类型,之所以特殊是因为它既是一种类(class)类型却...

  • 枚举

    枚举的定义方式 用枚举类型创建的对象(变量),值只能是枚举类型创建时所列举出的,不可以有其他值public enu...

  • Swift枚举和结构体(三)

    1. 枚举, 使用enum来创建枚举, 类似于类的命名类型, 枚举类型赋值可以是字符串/字符/整形/浮点型, 枚举...

  • C# Notizen 5 创建枚举类型和结构

    一、枚举类型枚举类型也成为枚举,它是一种创建数值类型的机制,这种值类型的可能取值是预定义的,而对于其中的每个可能取...

  • golang 基础(8)枚举类型

    枚举类型 在 go 语言中没特别地为枚举指定创建方法,可以通过定 func ,然后在其中创建静态变量来定义枚举。 ...

  • Java集合(十一)--EnumSet简析

    EnumSet是用于枚举类型的专用Set实现。EnumSet中的所有元素必须来自单个枚举类型,该类型在创建集时显式...

  • Swift学习笔记-枚举

    定义枚举类型 定义的语法和C/C++很像,只不过前面多了case语句 创建枚举实例 第一次创建枚举实例的时候必须指...

  • 枚举、元类和错误调试

    枚举 在各种编程语言中常用的枚举类型在python中当然不例外的也是有的,创建一个枚举非常简单,如下: 创建了一个...

  • 枚举那些事

    枚举是什么类型? 我们先创建一个枚举Alignment以上Alignment枚举被展开后的IL代码如下转化为机器语...

  • MyBatis中自定义类型处理器(TypeHandler)

    1.创建数据表Status 2.创建实体类UserStatus 其中Status是一个枚举类型 3.创建对应的类型...

网友评论

      本文标题:动态创建枚举类型

      本文链接:https://www.haomeiwen.com/subject/ldtaahtx.html