枚举工具类-反射获取枚举类中变量的所有值
2 年前
开发背景:
在开发中需要用到枚举类中变量的所有值。如下例季节枚举类中需要获取数组["春", "夏", "秋", "冬"]。
public enum Season {
SPRING("春天"),
SUMMER("夏天"),
AUTUMN("秋天"),
WINTER("冬天");
String season;
Season(String season) {
this.season = season;
public String getSeason() {
return season;
}
最开始,我使用传统的方式获取,代码如下:
public class EnumUtilsDemo {
public static void main(String[] args) {
List<String> seaconList = new ArrayList<>();
for (Season value : Season.values()) {
String season = value.getSeason();
seaconList.add(season);
System.out.println(seaconList);
}
由于最近在学习到了反射相关的知识,所以想编写利用反射编写一个通用的工具类。一来强化学习,一来以后可以通用工具类。
我的实现思路是这样的:通过分析上述代码发现,获取所有值需要知道所在的枚举类和要获取的字段。这里我发现枚举类中的Field类型有(以Season为例)如下:
Arrays.stream(Season.class.getDeclaredFields()).forEach(System.out::println);
public static final model.Season model.Season.SPRING
public static final model.Season model.Season.SUMMER
public static final model.Season model.Season.AUTUMN
public static final model.Season model.Season.WINTER
java.lang.String model.Season.season
private static final model.Season[] model.Season.$VALUES
所以我通过传入枚举类的class与要获取值的类型的class来获取。以Season为例,传入Season.class,与字段season的String.class来获取。
具体实现如下:
public class EnumUtils {
* 获取枚举类中变量的列表
* @param enumClass 枚举类的class
* @param paramClass 参数类型的class
* @param <E, T>
* @return
* @throws NoSuchMethodException
* @throws InvocationTargetException
* @throws IllegalAccessException
public static <E, T> List<T> getValues(Class<E> enumClass, Class<T> paramClass)
throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
E[] values = values(enumClass);
Field field = getField(enumClass, paramClass);
//因为枚举中字段的可能设置为private,要通过Field.get()方法获取Field的值需要开启忽略获取访问符限制
field.setAccessible(true);
List<T> resultList = new ArrayList<>();
for (E e : values) {
T t = (T)field.get(e);
resultList.add(t);
return resultList;
* 通过反射调用枚举类的values获取所有枚举类
* @param enumClass
* @param <E>
* @return
* @throws NoSuchMethodException
* @throws InvocationTargetException
* @throws IllegalAccessException
private static <E> E[] values(Class<E> enumClass)
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Method valuesMethod = enumClass.getMethod("values");
Object valuesObj = valuesMethod.invoke(enumClass);
E[] values = (E[]) valuesObj;
return values;
* 通过field的类型获取field
* 说明:
* 因为枚举类中只有Enum类型的Field,所有可以通过指定Field的类型来获取Field
* @param enumClass
* @param paramClass
* @param <E>
* @param <T>
* @return
private static <E, T> Field getField(Class<E> enumClass, Class<T> paramClass) throws IllegalAccessException {
//如果是包装类获取包装类的基本类型
Class basicClass = getBasicClass(paramClass);
//获取类型相同的Field(类型相同或与其基本类型相同)
List<Field> fieldList = Arrays.stream(enumClass.getDeclaredFields())
.filter(f -> f.getType() == paramClass || f.getType() == basicClass).collect(Collectors.toList());
if (fieldList.size() != 1) {
//抛出异常,只支持一个属性
throw new IllegalArgumentException(paramClass + "类型属性数量异常。");
return fieldList.get(0);
* 获取class的基本类型的class
* 说明:
* 存在基本类型将返回其基本类型,否则返回null
* 如传入Integer.class将返回int.class,传入String.class返回null
* @param paramClass
* @return
* @throws IllegalAccessException
private static Class getBasicClass(Class paramClass) throws IllegalAccessException {
Field typeField = null;
try {
//尝试获取包装类的TYPE
typeField = paramClass.getField("TYPE");
} catch (NoSuchFieldException e) {
return null;
//获取包装类TYPE成功,获取TYPE属性值(因为类型为static,所以传入null)
return (Class) typeField.get(null);
注释:这里我单独说下上述的getBasicClass方法:
- 通过Integer的源码public static final Class<Integer> TYPE = (Class<Integer>) Class.getPrimitiveClass("int");可以得知TYPE属性存放了其基本类型。
- 首先尝试通过class的getField("TYPE")获取TYPE属性。
- 如果获取TYPE属性成功,则将通过Field中的get(Object obj)获取TYPE属性中的值。
- 通过Field源码中get方法的注释可以得知,获取静态的Filed传入的Object为null即可,(因为static属于类不属于对象,所以无需指明具体的对象)
测试一下:
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
//原始方式获取
List<String> seaconList = new ArrayList<>();
for (Season value : Season.values()) {
String season = value.getSeason();
seaconList.add(season);
System.out.println(seaconList);
//反射工具类获取
List<String> values = getValues(Season.class, String.class);
System.out.println(values);
原始方式获取:[春, 夏, 秋, 冬]
反射工具类获取:[春, 夏, 秋, 冬]
这里需要说明,需要获取属性的类型只能存在一个,否则会无法正常获取,如下列枚举类Season新增字段String name,再次运行将导致程序异常。这种情况下只能用原始方式获取了。
public enum Season {
SPRING("春", "SPRING"),
SUMMER("夏", "SUMMER"),
AUTUMN("秋", "AUTUMN"),
WINTER("冬", "WINTER");
String season;
String name;
Season(String season, String name) {
this.season = season;
this.name = name;
public String getSeason() {
return season;
public String getName() {
return name;
}
再次运行输出:
再次运行输出: