基于枚举实现接口的泛型类,如何设置ID枚举默认值?
解决方案分析
首先说原代码报错的根本原因:泛型类型擦除。运行时T.class会被擦除为SortColumnType.class,而这是个接口不是枚举类,所以Enum.valueOf必然抛出异常。
要在无参构造下给sortColumn设置默认的ID枚举值,有两种可行方案,且都能通过创建公共类实现:
方案1:创建泛型子类 + 反射查找枚举常量
- 原接口和枚举类保持不变。
- 修改
SortColumn类,通过初始化块配合反射获取实际泛型类型,再定位到ID枚举:
@Setter @NoArgsConstructor public class SortColumn<T extends SortColumnType> { private T sortColumn; private SortType sortDirection = SortType.ASC; @SuppressWarnings("unchecked") { try { Type genericSuperclass = getClass().getGenericSuperclass(); // 只有通过指定具体泛型的子类实例化,才能获取到实际泛型类型 if (!(genericSuperclass instanceof ParameterizedType)) { throw new IllegalStateException("请使用指定具体泛型的子类创建实例,例如OneSortColumn"); } ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass; Class<T> enumClass = (Class<T>) parameterizedType.getActualTypeArguments()[0]; // 遍历枚举常量,筛选出名为"ID"的实例 for (T constant : enumClass.getEnumConstants()) { if (constant.name().equals("ID")) { sortColumn = constant; break; } } if (sortColumn == null) { throw new IllegalArgumentException("枚举类 " + enumClass.getName() + " 中不存在名为ID的常量"); } } catch (Exception e) { throw new RuntimeException("初始化默认排序字段失败", e); } } }
- 为每个枚举类创建对应的公共子类:
// 对应OneSortColumnType的子类 public class OneSortColumn extends SortColumn<OneSortColumnType> {} // 对应SecondSortColumnType的子类 public class SecondSortColumn extends SortColumn<SecondSortColumnType> {}
- 使用时直接调用无参构造:
SortColumn<OneSortColumnType> sortCol = new OneSortColumn(); // 此时sortCol的sortColumn即为OneSortColumnType.ID
方案2:给枚举类添加统一静态方法 + 反射调用
- 给每个实现
SortColumnType的枚举类添加getDefault()静态方法,返回ID实例:
public enum OneSortColumnType implements SortColumnType { ID("id"), NAME("name"); private final String name; OneSortColumnType(String name) { this.name = name; } @Override public String getName() { return name; } public static OneSortColumnType getDefault() { return ID; } } public enum SecondSortColumnType implements SortColumnType { ID("id"), DATE("date"); private final String name; SecondSortColumnType(String name) { this.name = name; } @Override public String getName() { return name; } public static SecondSortColumnType getDefault() { return ID; } }
- 修改
SortColumn类,通过反射调用枚举的getDefault()方法:
@Setter @NoArgsConstructor public class SortColumn<T extends SortColumnType> { private T sortColumn; private SortType sortDirection = SortType.ASC; @SuppressWarnings("unchecked") { try { Type genericSuperclass = getClass().getGenericSuperclass(); if (!(genericSuperclass instanceof ParameterizedType)) { throw new IllegalStateException("请使用指定具体泛型的子类创建实例"); } ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass; Class<T> enumClass = (Class<T>) parameterizedType.getActualTypeArguments()[0]; Method getDefaultMethod = enumClass.getMethod("getDefault"); sortColumn = (T) getDefaultMethod.invoke(null); } catch (Exception e) { throw new RuntimeException("初始化默认排序字段失败", e); } } }
- 同样通过对应公共子类的无参构造实例化即可。
关于公共类的可行性
当然可以通过公共类实现需求。上述两种方案中的OneSortColumn、SecondSortColumn就是公共类,它们明确指定了泛型的实际类型,让反射能够获取到枚举类的Class对象,从而正确初始化默认的ID枚举值。
内容的提问来源于stack exchange,提问作者wuttke
相关产品推荐
相关产品推荐

