generics和类<? 扩展Enum >,EnumSet.allOf(class)vs class.getEnumConstants()
我有以下BeanValidation代码可以正常工作,并允许validation带有注释的bean:
@EnumValue(enumClass = MyTestEnum.class) private String field; public enum MyTestEnum { VAL1, VAL2; }
仅当字段值为“VAL1”或“VAL2”时才会进行validation。
public class EnumNameValidator implements ConstraintValidator { private Set AVAILABLE_ENUM_NAMES; @Override public void initialize(EnumValue enumValue) { Class<? extends Enum> enumSelected = enumValue.enumClass(); Set<? extends Enum> enumInstances = Sets.newHashSet(enumSelected.getEnumConstants()); AVAILABLE_ENUM_NAMES = FluentIterable .from(enumInstances) .transform(PrimitiveGuavaFunctions.ENUM_TO_NAME) .toImmutableSet(); } @Override public boolean isValid(String value, ConstraintValidatorContext context) { if ( value == null ) { return true; } else { return AVAILABLE_ENUM_NAMES.contains(value); } } }
我不明白的是为什么我的第一次尝试失败了。 使用以下代码上面的enumSelected.getEnumConstants()
代替:
Set<? extends Enum> enumInstances = EnumSet.allOf(enumSelected);
Intellij 12没有突出显示任何错误,但编译器说:
java: method allOf in class java.util.EnumSet cannot be applied to given types; required: java.lang.Class found: java.lang.Class<capture#1 of ? extends java.lang.Enum> reason: inferred type does not conform to declared bound(s) inferred: capture#1 of ? extends java.lang.Enum bound(s): java.lang.Enum<capture#1 of ? extends java.lang.Enum>
我不明白这个问题,我也有那个工作正常的代码:
private static <T extends Enum & EnumAlternativeName> T safeGetByAlternativeName(Class enumClass, String alternativeName) { for ( T t : EnumSet.allOf(enumClass) ) { if ( t.getAlternativeName().equals(alternativeName) ) { return t; } } return null; }
我猜是在? extends Enum>
? extends Enum>
这两个?
可能是不同的,而allOf
期望T extends Enum
,其中两个T
都相同。
例如,请考虑以下代码:
static enum MyEnum {} static class EnumValue> { Class enumClass; EnumValue(Class enumClass) { this.enumClass = enumClass; } Class enumClass() { return enumClass; } }
这些行将编译:
EnumValue> enumValue = new EnumValue(MyEnum.class); // raw constructor Set extends Enum>> enumInstances = EnumSet.allOf(enumValue.enumClass());
因为我们知道enumValue.enumClass()
中的两个T
是相同的但是不会:
EnumValue enumValue = new EnumValue(MyEnum.class); Class extends Enum>> enumSelected = enumValue.enumClass(); Set extends Enum>> enumInstances = EnumSet.allOf(enumSelected);
因为你使用Class extends Enum>>
丢失了信息 Class extends Enum>>
作为中间步骤。
我对@ assylias解决方案的解释:
我们想要表达的类的类型是它是一个
Class, for some E, that E <: Enum
但Java不允许我们在方法体中引入类型变量E
通常,我们可以利用通配符和通配符捕获来引入隐藏类型变量
class G { ... } // b(T) is a type expression that may contain T G extends A> --capture--> G , for some T, that T <: A & b(T)
但是这在我们的情况下不起作用,因为Class
中的Class
没有使其工作的界限。
所以我们需要引入一个具有所需边界的新类型
class EnumClass> // called EnumValue in assylias's solution EnumClass(Class enumClass) Class enumClass() EnumClass> --capture--> EnumClass , for some E, that E <: Enum
然后我们调用EnumClass
来产生一个
Class, for some E, that E <: Enum
这是我们一直努力实现的目标。
但是我们如何调用EnumClass
的构造EnumClass
呢? 问题的根源是我们没有适当的enumClass
类型,但enumClass
的构造函数EnumClass
一个正确类型的enumClass
。
Class enumClass = ...; new EnumClass<...>(enumClass); // wont work
幸运的是(?)原始类型有助于禁用generics类型检查
EnumClass raw = new EnumClass(enumClass); // no generics EnumClass> wild = raw;
因此,我们需要执行的最小体操才能将课程演绎到所需的类型
((EnumClass>)new EnumClass(enumClass)).enumClass()