【问题标题】:Enum.valueOf(Class<T> enumType, String name) questionEnum.valueOf(Class<T> enumType, String name) 问题
【发布时间】:2010-10-25 11:32:42
【问题描述】:

我正在尝试解决与动态枚举查找相关的编译错误(“绑定不匹配:...”)。

基本上我想实现这样的目标:

String enumName = whatever.getEnumName();
Class<? extends Enum<?>> enumClass = whatever.getEnumClass();
Enum<?> enumValue = Enum.valueOf(enumClass, enumName);

无论我做什么,我总是以编译错误告终。老实说,泛型和枚举对我来说非常令人难以置信......

我在这里做错了什么?

【问题讨论】:

    标签: java generics reflection enums


    【解决方案1】:

    我认为除非您可以访问类型变量(通过类型或方法签名),否则它不会完全像这样工作。问题是Enum.valueOf的方法签名:

    public static <T extends Enum<T>> T valueOf(
        Class<T> enumType,
        String name
    );
    

    没有类型变量就无法获得 T。但是如果你愿意禁止一些编译器警告,你可以这样做:

    public enum King{
        ELVIS
    }
    
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static void main(final String[] args){
        final Class<? extends Enum> enumType = King.class;
        final Enum<?> theOneAndOnly = Enum.valueOf(enumType, "ELVIS");
        System.out.println(theOneAndOnly.name());
    }
    

    输出:

    猫王

    【讨论】:

    • 问题是关于枚举、泛型和反射。如果你忽略泛型,那有什么意义呢?特别是像Class&lt;? extends Enum&gt;这样的“稀有类型”。
    • 重点是 a) 如果没有辅助方法或类型,它就无法工作,b) 我们确信任何 Class&lt;? extends Enum&gt; 也将满足 Class&lt;E extends Enum&lt;E&gt;&gt; (因为这就是 enum 的方式类工作)即使没有类型变量就无法检查。 @SuppressWarnings 是一个注释,只有当你知道自己在做什么时才应该使用,而且我知道。
    【解决方案2】:

    问题在于Class&lt;? extends Enum&lt;?&gt;&gt;。我们想要E extends Enum&lt;E&gt;,但我们无法得到它,因为我们有两个不同的通配符。

    所以我们需要引入一个泛型参数,可以通过调用方法引入:

    enum MyEnum {
        ME;
    }
    
    public class EnName {
        public static void main(String[] args) {
            Enum<?> value = of(MyEnum.class, "ME");
            System.err.println(value);
        }
        private static <E extends Enum<E>> E of(Class<E> clazz, String name) {
            E value = Enum.valueOf(clazz, name);
            return value;
        }
    }
    

    但是反射是肮脏的,很少是你想要的。不要这样做。

    【讨论】:

    • 感谢您的解释,它对进一步了解发生的事情有很大帮助。因为在我的特定用例中,我没有任何东西可以作为通用参数提供,所以我将寻求 seanizer 的答案。
    【解决方案3】:

    实际上还有另一种方法:您可以使用Class.getEnumConstants 并滚动您自己的Enum.valueOf 实现,它没有相同的类型问题。缺点是你会得到一个通用的Enum&lt;?&gt;——但如果你知道你输入的是什么类型,你无论如何都可以使用Enum.valueOf

    private static Enum<?> findEnumValue(Class<? extends Enum<?>> enumType, String value) {
        return Arrays.stream(enumType.getEnumConstants())
                     .filter(e -> e.name().equals(value))
                     .findFirst()
                     .orElse(null);
    }
    

    (请注意,如果没有这样的常量,我的版本会返回null,而不是抛出IllegalArgumentException,但这是一件微不足道的改变。

    【讨论】:

      【解决方案4】:

      谢谢@Sbodd 的答案。我举了这个例子,添加了我们从标准 anEnum.valueOf("ELVIS") 中知道的异常,并以我们可以像这样使用它的方式更改了通用方法 args:

             King king = findEnumValue(King.class, "ELVIS");
             System.out.println(String.valueOf(king)); 
      

      方法:

      /**
       * Returns the {@link Enum} for the given {@link Enum#name()} String of the given enum type. 
       * <p>
       * Example: 
       * <pre>
       * {@code     
            King king = findEnumValue(King.class, "ELVIS");
            System.out.println(String.valueOf(king));
       * }
       * </pre>
       * @param enumType the class of the enum, e.g. {@code King.class}. 
       * 
       * @param enumName the {@link Enum#name()}, e.g. "ELVIS". 
       * 
       * @return the enum instance or an exception. 
       * 
       * @throws IllegalArgumentException if the given {@code enumName} is no enum constant in the given {@code enumType}. 
       */
      public static <T extends Enum<T>> T findEnumValue(Class<T> enumType, String enumName) throws IllegalArgumentException {
          T result = Arrays.stream(enumType.getEnumConstants())
                       .filter(e -> e.name().equals(enumName))
                       .findFirst()
                       .orElse(null);
          if(result == null)
          {
              throw new IllegalArgumentException(
                          "No enum constant " + enumType.getCanonicalName() + "." + enumName);
          }
          else
          {
              return result;
          }
      }
      
      public enum King{
          ELVIS
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-11-01
        • 1970-01-01
        • 2021-08-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-09-01
        • 2011-12-03
        相关资源
        最近更新 更多