java 泛型和类<? 扩展 Enum<?>>、EnumSet.allOf(class) 与 class.getEnumConstants()
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15366375/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Generics and Class<? extends Enum<?>>, EnumSet.allOf(class) vs class.getEnumConstants()
提问by Sebastien Lorber
I have the following BeanValidation code that works fine, and permits to validate that a bean annotated with:
我有以下 BeanValidation 代码可以正常工作,并允许验证一个 bean 注释为:
@EnumValue(enumClass = MyTestEnum.class)
private String field;
public enum MyTestEnum {
VAL1, VAL2;
}
Will be validated only if the field value is "VAL1" or "VAL2".
仅当字段值为“VAL1”或“VAL2”时才会被验证。
public class EnumNameValidator implements ConstraintValidator<EnumValue, String> {
private Set<String> 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);
}
}
}
What I don't understand is why my first attempt failed. Using instead of the enumSelected.getEnumConstants()
above the following code:
我不明白的是为什么我的第一次尝试失败了。使用enumSelected.getEnumConstants()
以下代码代替上述代码:
Set<? extends Enum<?>> enumInstances = EnumSet.allOf(enumSelected);
Intellij 12 doesn't highlight any error, but the compiler says:
Intellij 12 没有突出显示任何错误,但编译器说:
java: method allOf in class java.util.EnumSet<E> cannot be applied to given types;
required: java.lang.Class<E>
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<?>>
I don't understand the problem, and I also have that code which works fine:
我不明白这个问题,我也有可以正常工作的代码:
private static <T extends Enum<T> & EnumAlternativeName> T safeGetByAlternativeName(Class<T> enumClass, String alternativeName) {
for ( T t : EnumSet.allOf(enumClass) ) {
if ( t.getAlternativeName().equals(alternativeName) ) {
return t;
}
}
return null;
}
采纳答案by assylias
My guess is that in ? extends Enum<?>
the two ?
could be different whereas allOf
expects a T extends Enum<T>
where both T
are the same.
我的猜测是? extends Enum<?>
两者?
可能不同,而allOf
期望T extends Enum<T>
两者T
相同。
For example, consider the following code:
例如,考虑以下代码:
static enum MyEnum {}
static class EnumValue<T extends Enum<T>> {
Class<T> enumClass;
EnumValue(Class<T> enumClass) {
this.enumClass = enumClass;
}
Class<T> enumClass() { return enumClass; }
}
These lines will compile:
这些行将编译:
EnumValue<?> enumValue = new EnumValue(MyEnum.class); // raw constructor
Set<? extends Enum<?>> enumInstances = EnumSet.allOf(enumValue.enumClass());
because we know that the two T
in enumValue.enumClass()
are the same but this won't:
因为我们知道两个T
inenumValue.enumClass()
是相同的,但这不会:
EnumValue enumValue = new EnumValue(MyEnum.class);
Class<? extends Enum<?>> enumSelected = enumValue.enumClass();
Set<? extends Enum<?>> enumInstances = EnumSet.allOf(enumSelected);
because you have lost information by using a Class<? extends Enum<?>>
as an intermediate step.
因为您使用 aClass<? extends Enum<?>>
作为中间步骤丢失了信息。
回答by ZhongYu
My explanation on @assylias's solution:
我对@assylias 解决方案的解释:
What we want to express about the type of the class is that it's a
关于类的类型,我们想表达的是它是一个
Class<E>, for some E, that E <: Enum<E>
but Java does not allow us to introduce a type variable E
in a method body.
但是 Java 不允许我们E
在方法体中引入类型变量。
Usually, we can exploit wildcard and wildcard capture to introduce a hidden type variable
通常,我们可以利用通配符和通配符捕获来引入隐藏类型变量
class G<T extends b(T)> { ... } // b(T) is a type expression that may contain T
G<? extends A> --capture--> G<T>, for some T, that T <: A & b(T)
But this won't work in our case, since T
in Class<T>
does not have a bound that makes it work.
但这在我们的情况下不起作用,因为T
inClass<T>
没有使其工作的界限。
So we need to introduce a new type with the desired bound
所以我们需要引入一个具有所需边界的新类型
class EnumClass<E extends Enum<E>> // called EnumValue in assylias's solution
EnumClass(Class<E> enumClass)
Class<E> enumClass()
EnumClass<?> --capture--> EnumClass<E>, for some E, that E <: Enum<E>
We then call EnumClass<E>.enumClass()
to yield a
然后我们调用EnumClass<E>.enumClass()
以产生一个
Class<E>, for some E, that E <: Enum<E>
which is the goal we've been trying to achieve.
这是我们一直在努力实现的目标。
But how can we call the constructor of EnumClass
? The origin of the problem is that we don't have a proper type for enumClass
, yet the constructor of EnumClass
wants a properly typed enumClass
.
但是我们如何调用 的构造函数EnumClass
呢?问题的根源在于我们没有正确的类型enumClass
,但是 的构造函数EnumClass
想要正确类型的enumClass
。
Class<not-proper> enumClass = ...;
new EnumClass<...>(enumClass); // wont work
Fortunately(?) the raw type helps here which disables generics type checking
幸运的是(?)原始类型在这里有帮助,它禁用了泛型类型检查
EnumClass raw = new EnumClass(enumClass); // no generics
EnumClass<?> wild = raw;
So the minimum gymnastics we need to perform to cast the class to the desired type is
所以我们需要执行的最小体操是将类转换为所需的类型
((EnumClass<?>)new EnumClass(enumClass)).enumClass()