Java枚举构造器传入泛型基类实例无法获取对应泛型类型问询
Java 语法规定枚举类本身不能声明泛型参数,因此你无法为每个枚举常量绑定独立的泛型类型,这是你无法直接在枚举中保留Field<T>泛型信息的核心原因,以下是三种可行的实现方案:
- 方案一:最简修改,添加unchecked警告抑制
你在构造枚举常量时已经保证了每个枚举对应的Field类型是确定的,因此可以直接在get方法中添加强转和警告抑制,编译器会自动做调用侧的类型推导:
public enum Fields { INTEGER (new IntegerField()), STRING (new StringField()); private final Field<?> field; <T> Fields(Field<T> field) { this.field = field; } @SuppressWarnings("unchecked") public <T> T get() { return (T) field.get(); } }
调用示例:
// 不需要手动强转,编译器自动推导类型为Integer Integer intVal = Fields.INTEGER.get(); // 不需要手动强转,编译器自动推导类型为String String strVal = Fields.STRING.get();
注意:该方案的类型安全由开发者自行保证,如果调用时赋值给错误类型的变量,运行时会抛出ClassCastException。
- 方案二:类型安全转换方案
如果想要消除unchecked警告,同时让类型转换错误的提示更明确,可以在构造枚举时额外传入对应类型的Class对象,调用get时通过Class.cast做安全转换:
public enum Fields { INTEGER (new IntegerField(), Integer.class), STRING (new StringField(), String.class); private final Field<?> field; private final Class<?> type; <T> Fields(Field<T> field, Class<T> type) { this.field = field; this.type = type; } @SuppressWarnings("unchecked") public <T> T get() { return (T) type.cast(field.get()); } }
- 方案三:编译期完全类型安全方案
如果完全不想承担运行时类型转换的风险,可以放弃使用枚举,改用普通类定义静态常量,这样每个常量可以保留独立的泛型信息:
public final class Fields<T> { public static final Fields<Integer> INTEGER = new Fields<>(new IntegerField()); public static final Fields<String> STRING = new Fields<>(new StringField()); // 如需枚举的遍历能力,可手动维护全量常量列表 public static final List<Fields<?>> ALL_VALUES = List.of(INTEGER, STRING); private final Field<T> field; private Fields(Field<T> field) { this.field = field; } public T get() { return field.get(); } }
该方案的优势是所有类型检查都在编译期完成,不会出现运行时类型转换错误,缺点是无法直接使用枚举原生的values()、valueOf()等内置方法。
内容的提问来源于stack exchange,提问作者Ian
相关产品推荐
相关产品推荐

