项目里,经常涉及到枚举类的使用。利用反射实现根据枚举值获取枚举对象,可以方便我们对该枚举对象的直接操作。
通过值实例化枚举
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