泛型和类>,EnumSet.allOf(class)vs class.getEnumConstants()

时间:2023-01-26 13:19:30

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;
  }

2 个解决方案

#1


8  

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.

我猜是在?扩展Enum <?>这两个?可能是不同的,而allOf期望T扩展Enum ,其中两个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:

因为我们知道enumValue.enumClass()中的两个T是相同的但是不会:

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.

因为你使用Class <?丢失了信息扩展Enum <?>>作为中间步骤。

#2


3  

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.

但是这在我们的情况下不起作用,因为Class 中的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 .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()

#1


8  

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.

我猜是在?扩展Enum <?>这两个?可能是不同的,而allOf期望T扩展Enum ,其中两个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:

因为我们知道enumValue.enumClass()中的两个T是相同的但是不会:

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.

因为你使用Class <?丢失了信息扩展Enum <?>>作为中间步骤。

#2


3  

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.

但是这在我们的情况下不起作用,因为Class 中的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 .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()