我在Java程序中编写了这个函数:
public <T extends Enum<T>> T getEnum(Class<T> enumClass, String name) {
String value = get(name);
if (value == null) return null;
if (value.length() == 0) return null;
return Enum.valueOf(enumClass, value);
}我就是这么叫它的:
CollegeDegreeType degreeType = model.getEnum(CollegeDegreeType.class, "degree_type");它可以工作,但我觉得我应该能够省略第一个参数,并从返回类型(结果被分配到的类型)推断它。这个是可能的吗?如果是的话,语法是什么?
发布于 2022-05-01 21:09:55
让我问你:如果没有仿制药,你会怎么做?如果没有泛型就无法做到这一点,那么也不能用泛型来完成。泛型在编译时被擦除,在运行时不存在(除了类、字段和方法声明中的泛型可以在运行时从类文件中检查,但在这里不相关)。所以,如果它可以用泛型来完成,你必须能够擦除它并且不使用泛型。
删除的原始方法如下所示:
public Enum getEnum(Class enumClass, String name) {
String value = get(name);
if (value == null) return null;
if (value.length() == 0) return null;
return Enum.valueOf(enumClass, value);
}但你想做这样的事:
public Enum getEnum(String name) {
String value = get(name);
if (value == null) return null;
if (value.length() == 0) return null;
return ???
}这是不可能的即使Java没有泛型,Enum.valueOf()仍然需要在运行时使用enumClass,因为它知道在哪个枚举中查找名称。实际上,可以有多个同名常量的枚举,而EnumA.SOME_CONSTANT在运行时将是一个与EnumB.SOME_CONSTANT不同的对象,那么它如何知道您想要哪个对象呢?它不能。
也许您认为泛型方法会以某种方式传递其泛型参数(这里是T)。但这不是一般方法的意思。当您在T上编写泛型方法时,这意味着您的方法的运行时字节码对于任何T (在T的范围内)都必须是正确的,而不知道T是什么。调用方可以期望您的方法在某种程度上只起作用,不管T是什么(实际上,调用方甚至可能不知道T是什么)。
发布于 2022-04-29 18:16:09
它可以工作,但我觉得我应该能够省略第一个参数,并从返回类型推断它。
您将无法在运行时提供T,除非您有以下任何一种:
T (您想省略它);T是方法调用的结果;f 212
示例(第二个和第三个选项)
public static <T extends Enum<T>> T getEnum(String name) {
T myEnum = (T) getHardCodedEnumMember();
return (T) Enum.valueOf(myEnum.getClass(), name);
}
public static <T extends Enum<T>> T getHardCodedEnumMember() {
return (T) DayOfWeek.SATURDAY;
}这是可行的,但我想这不是您的意图,所以我必须坚持将Class实例作为参数传递。
另一件需要考虑的事情是,您列出的方法可能有三个结果:
null值;如果没有具有匹配名称的枚举成员,valueOf()将抛出IllegalArgumentException。而且,预先检查null和空字符串不会将您从它中拯救出来。同时,您需要处理一个可空的结果。
您可以采取另一种方法,消除运行时异常,并将可能的结果减少为包含结果的空可选或可选结果。为此,您可以使用EnumSet.allOf()检索所有特定枚举类型的内容。
public <T extends Enum<T>> Optional<T> getEnum(Class<T> enumClass, String name) {
String value = get(name);
if (value == null || value.length() == 0) {
return Optional.empty();
}
return EnumSet.allOf(enumClass).stream()
.filter(element -> element.name().equals(value))
.findFirst();
}发布于 2022-04-29 19:43:31
由于泛型类型擦除--只有在编译时才知道T类型,这将阻止您在运行时访问它的类,而这是Enum.valueOf所需的。
请参阅https://docs.oracle.com/javase/tutorial/java/generics/erasure.html
在某些情况下,可以从技术上检索泛型类型,请参阅Get generic type of class at runtime。
但我不认为这会提高代码的质量。在我看来,你目前获得这门课的解决方案是一种很好的方法。
一个可以工作的示例实现,但在我看来是hacky* (*由于未检查的转换、反射和匿名类实现/扩展语法要求):
public abstract class MyEnumParser<T extends Enum<T>> {
public T parseEnum(String value) {
return Enum.valueOf(getEnumClass(), value);
}
private Class<T> getEnumClass() {
return (Class<T>) ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];
}
}用法:
MyEnumParser<CollegeDegreeType> parser = new MyEnumParser<>() {};
System.out.println(parser.parseEnum("degree_type"));https://stackoverflow.com/questions/72060257
复制相似问题