根据code值获取内部枚举类对象(自定义EnumUtil,PackageUtil工具类)

本文介绍了如何在项目中根据枚举值获取枚举对象,提供两种实现方式:1. 直接使用反射;2. 在程序启动时将所有枚举类加载到Map中。此外,还讨论了在使用`PackageUtils`获取类路径时遇到的问题,即在Tomcat环境下`getSystemResource("")`返回空指针。问题的根源在于不同的ClassLoader,解决方案是使用当前类的ClassLoader来获取资源。最后,给出了`EnumUtils`工具类的示例和测试情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

项目里,经常涉及到枚举类的使用。利用反射实现根据枚举值获取枚举对象,可以方便我们对该枚举对象的直接操作。

通过值实例化枚举

package com.rq.enumutils.utils;

import com.rq.enumutils.service.EnumMessage;

public class EnumUtil {

    /**
     * 返回指定编码的'枚举'针对实现EnumMessage接口的枚举类
     * @param code
     * @return SharedObjTypeEnum
     * @throws
     */
    public static <T extends EnumMessage> T getEnumBycode(Class<T> clazz, String code) {
        for(T inner : clazz.getEnumConstants())
            if(code.equals(inner.getCode()))
                return inner;
        return null;
    }


    /**
     * 返回指定描述的'枚举'
     * @param desc
     * @return SharedObjTypeEnum
     * @throws
     */
    public static <T extends EnumMessage> T getEnumByDesc(Class<T> clazz, String desc) {
        for(T inner : clazz.getEnumConstants())
            if(inner.getDesc().equals(desc))
                return inner;
        return null;
    }
}

另一种实现方案:在程序启动时完成所有枚举类的加载,并填入map集合中(之后操作都从该集合中获取)
参考地址:https://www.cnblogs.com/jian-xiao/p/6036925.html

package com.rq.enumutils.common;

import com.rq.enumutils.service.EnumMessage;
import com.rq.enumutils.utils.PackageUtils;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 通过code值获取枚举对象
 * 具体代码实现:
 *
 *   1).定义一个EnumMessage接口,然后每个枚举类实现此接口;
 *
 *   2).定义常量保存枚举类所在包名,以及接口全路径;
 *
 *   3).在程序启动时,读取枚举类所在包下的所有枚举类的File文件,在从file文件信息中获取每个枚举类的全路径类名集合A;
 *
 *   4).遍历A集合,利用反射获取每个类的class对象,再判断该类是否实现了EnumMessage接口;
 *
 *   5).对于实现了EnumMessage接口的枚举类,遍历该枚举类的所有对象,保存Map<Object, EnumMessage>的集合映射;
 *
 *   6).对枚举类保存Map<Class, Map<Object, EnumMessage>>的映射集合。
 */
public class Constant {
    /**
     * 枚举类包名集合
     */
    public static List<String> pathList = initPackagePathList();
    /**
     * 枚举接口类全路径
     */
    public final static String ENUM_MESSAGE_PATH = "com.rq.enumutils.service.EnumMessage";

    /**
     * 枚举类对应的全路径集合
     */
    public static final List<String> ENUM_OBJECT_PATH = PackageUtils.getPackageClasses(pathList, true);

    /**
     * 存放单个枚举对象 map常量定义
     */
    private static Map<Object, EnumMessage> SINGLE_ENUM_MAP = null;

    /**
     * 所有枚举对象的 map
     */
    public static final Map<Class, Map<Object, EnumMessage>> ENUM_MAP = initialEnumMap(true);

    private static List<String> initPackagePathList() {
        List<String> list = new ArrayList<>();
        list.add("com.rq.enumutils.enums");
        return list;
    }

    /**
     * 加载所有枚举对象数据
     *
     * @param isFouceCheck 是否强制校验枚举是否实现了EnumMessage接口,若为false则没有实现接口的枚举类也会被加载
     */
    private static Map<Class, Map<Object, EnumMessage>> initialEnumMap(boolean isFouceCheck) {
        Map<Class, Map<Object, EnumMessage>> ENUM_MAP = new HashMap<>();
        try {
            for (String classname : ENUM_OBJECT_PATH) {
                Class<?> cls =  Class.forName(classname);
                //获取实现的接口列表
                Class<?>[] iter = cls.getInterfaces();
                boolean flag = false;
                if (isFouceCheck) {
                    for (Class cz : iter) {
                    	//找出实现目标接口的类
                        if (cz.getName().equals(ENUM_MESSAGE_PATH)) {
                            flag = true;
                            break;
                        }
                    }
                }
                if (flag == isFouceCheck) {
                	//自定义map集合,添加该枚举类的所有内部枚举类,
                    SINGLE_ENUM_MAP = new HashMap<>();
                    initialSingleEnumMap(cls);
                    //将新创建的map集合加入到ENUM_MAP集合中
                    ENUM_MAP.put(cls, SINGLE_ENUM_MAP);
                }

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

    /**
     * 加载每个枚举对象数据
     */
    private static void initialSingleEnumMap(Class<?> cls) throws Exception {
    	//通过反射调用values方法
        Method method = cls.getMethod("values");
        EnumMessage inter[] = (EnumMessage[]) method.invoke(null, null);
        for (EnumMessage enumMessage : inter) {
            SINGLE_ENUM_MAP.put(enumMessage.getCode(), enumMessage);
        }
    }
}

接口类

package com.rq.enumutils.service;

public interface EnumMessage {
    String getCode();
    String getDesc();
}

PackageUtils

package com.rq.enumutils.utils;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class PackageUtils {
    /**
     * 返回包下所有的类
     *
     * @param packagePathList   包名全路径集合
     * @param classWithPath 返回全路径开关 true 自动带上包名 false 只返回类名
     * @return List<String> 包下所有的类
     */
    public static List<String> getPackageClasses(List<String> packagePathList, boolean classWithPath) {
        List<String> result = new ArrayList<>();
        for(String packagePath : packagePathList) {
            List<String> classNames = getClassName(packagePath);
            String path = classWithPath ? packagePath + "." : "";
            for (String className : classNames) {
                //className:com.example.myFirstProject.enums.SexEnum
                result.add(path + className.substring(className.lastIndexOf(".") + 1));
            }
        }
        return result;
    }

    /**
     * 获取该包名全路径下的所有class全路径集合
     * @param packageName 包名全路径
     * @return
     */
    private static List<String> getClassName(String packageName) {
        //根据包名获取该package的系统路径
        String filePath = ClassLoader.getSystemResource("").getPath() + packageName.replace(".", "\\");
        // filePath: /D:/workspace/enumutils/target/classes/com\rq\enumutils\enums
        List<String> classNames = new ArrayList<>();
        //注意:区别测试环境与开发环境
        List<String> fileNames = getClassName(filePath.replace("test-classes","classes"), classNames);
        return fileNames;
    }

    /**
     * 获取filePath文件夹下的所有class的全路径集合
     * @param filePath
     * @param className
     * @return
     */
    private static List<String> getClassName(String filePath, List<String> className) {
        File file = new File(filePath);
        File[] childFiles = file.listFiles();
        if (childFiles != null) {
            for (File childFile : childFiles) {
                if (childFile.isDirectory()) {
                    //递归获取该文件夹下的子文件夹里的所有文件
                    className.addAll(getClassName(childFile.getPath(), className));
                } else {
                    String childFilePath = childFile.getPath();
                    //childFilePath:  D:\workspace\enumutils\target\classes\com\rq\enumutils\enums\Sex.class
                    childFilePath = childFilePath.substring(childFilePath.indexOf("\\classes") + 9, childFilePath.lastIndexOf("."));
                    childFilePath = childFilePath.replace("\\", ".");
                    className.add(childFilePath);
                }
            }
        }

        return className;
    }
}

这里有个小坑
在getClassName()方法里,如果用tomcat启动项目,getSystemResource("")会返回空指针
了解 getSystemResource(Stringname)、getSystemResourceAsStream(Stringname)、getSystemResources(Stringname)
内部实现的时候都是用到了ClassLoader system = getSystemClassLoader();的方法,获取的ClassLoader都是App ClassLoader所以在使用tomcat运行的时候就会取不到classPath路径下的资源,因为都是WebappClassLoader加载的。详情点击https://www.aliyun.com/jiaocheng/864751.html

解决办法:
使用当前类.class.getClassLoader().getResource(Stringname)、getResourceAsStream(Stringname)、getResources(Stringname)这三种方法。

工具类EnumUtils

package com.rq.enumutils.utils;


import com.rq.enumutils.common.Constant;
import com.rq.enumutils.service.EnumMessage;

/**
 * 获取内部枚举类对象
 */
public class EnumUtils {
    /**
     * 获取value返回枚举对象
     * @param value 内部枚举类code值
     * @param clazz 需要解析的枚举类
     * */
    public static <T extends EnumMessage>  T getEnumObject(Object value, Class<T> clazz){
        if (value == null || clazz == null) {
            return null;
        }
        return (T) Constant.ENUM_MAP.get(clazz).get(value);
    }
}

测试:

    @Test
    public void contextLoads() {
        String line = "佩奇 123 00 03";
        String line2 = "米奇 312 01 04";
        String line3 = "青霞 111 00 04";
        User user = DataUtils.Str2Obj(line, " ", User.class, 0);
        User user2 = DataUtils.Str2Obj(line2, " ", User.class, 0);
        User user3 = DataUtils.Str2Obj(line3," ",User.class,0);
        System.out.println("user1:---"+user);
        System.out.println("user2:---"+user2);
        System.out.println("user3:---"+user3);
    }

输出:
在这里插入图片描述

实例下载:https://download.youkuaiyun.com/download/qq_41981107/10859325

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值