【问题标题】:Iterate enum values using java generics使用 java 泛型迭代枚举值
【发布时间】:2010-02-05 08:32:04
【问题描述】:

我正在尝试找到一种在使用泛型时迭代枚举值的方法。不确定如何执行此操作或是否可能。

以下代码说明了我想要做什么。请注意,代码 T.values() 在以下代码中无效。

public class Filter<T> {
    private List<T> availableOptions = new ArrayList<T>();
    private T selectedOption;

    public Filter(T selectedOption) {
        this.selectedOption = selectedOption;
        for (T option : T.values()) {  // INVALID CODE
            availableOptions.add(option);
        }
    }
}

下面是我将如何实例化一个 Filter 对象:

Filter<TimePeriod> filter = new Filter<TimePeriod>(TimePeriod.ALL);

枚举定义如下:

public enum TimePeriod {
    ALL("All"), 
    FUTURE("Future"), 
    NEXT7DAYS("Next 7 Days"), 
    NEXT14DAYS("Next 14 Days"), 
    NEXT30DAYS("Next 30 Days"), 
    PAST("Past"),
    LAST7DAYS("Last 7 Days"), 
    LAST14DAYS("Last 14 Days"),
    LAST30DAYS("Last 30 Days"); 

    private final String name;

    private TimePeriod(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return name;
    }
}

我意识到将枚举的值复制到列表中可能没有意义,但我使用的库需要值列表作为输入并且不适用于枚举。


2010 年 2 月 5 日编辑:

提出的大多数答案都非常相似,建议这样做:

class Filter<T extends Enum<T>> {
    private List<T> availableOptions = new ArrayList<T>();
    private T selectedOption;

    public Filter(T selectedOption) {
        Class<T> clazz = (Class<T>) selectedOption.getClass();
        for (T option : clazz.getEnumConstants()) {
            availableOptions.add(option);
        }
    }
}

如果我可以确定 selectedOption 具有非空值,这将非常有用。不幸的是,在我的用例中,这个值通常为空,因为还有一个 public Filter() 无参数构造函数。这意味着我不能在没有 NPE 的情况下执行 selectedOption.getClass() 。此过滤器类管理一个可用选项列表,其中哪些选项被选中。未选择任何内容时, selectedOption 为 null。

我想解决这个问题的唯一方法是在构造函数中实际传入一个类。所以是这样的:

class Filter<T extends Enum<T>> {
    private List<T> availableOptions = new ArrayList<T>();
    private T selectedOption;

    public Filter(Class<T> clazz) {
        this(clazz,null);
    }

    public Filter(Class<T> clazz, T selectedOption) {
        this.selectedOption = selectedOption;
        for (T option : clazz.getEnumConstants()) {
            availableOptions.add(option);
        }
    }
}

任何想法如何在构造函数中不需要额外的 Class 参数的情况下做到这一点?

【问题讨论】:

标签: java generics enums enumeration


【解决方案1】:

这确实是一个难题。您需要做的一件事是告诉 java 您正在使用枚举。这是通过声明您为泛型扩展 Enum 类。然而这个类没有 values() 函数。因此,您必须选择可以获取值的类。

以下示例应该可以帮助您解决问题:

public <T extends Enum<T>> void enumValues(Class<T> enumType) {
        for (T c : enumType.getEnumConstants()) {
             System.out.println(c.name());
        }
}

【讨论】:

  • c.name() 不是返回枚举项的名称吗?如何返回它的值?比如说,对于 QUIZ("quizzie") 项目,返回“quizzie”而不是 QUIZ。
  • 为此,您需要在枚举上有一个返回值的方法,例如:getFriendlyName()。然后你必须为你的枚举添加一个接口,然后调整上面的泛型以要求枚举和类型T的接口。然后函数变为:public &lt;E extends Enum&lt;?&gt; &amp; EnumWithFriendlyName&gt; void friendlyEnumValues(Class&lt;T&gt; enumType)
  • 我能否详细了解如何编写类型 T 的接口或任何可以找到示例的链接,因为我正在寻找检索值。
  • @SonaliGupta 它与任何其他接口的机制相同。您使用函数getFriendlyName() 定义一个接口,然后在枚举中使用“implements EnumWithFriendlyName”来实现该接口,并且您的函数想要使用枚举的接口函数,您可以按照我在之前的评论中显示的那样进行操作。
【解决方案2】:

另一种选择是使用 EnumSet:

class PrintEnumConsants {

    static <E extends Enum <E>> void foo(Class<E> elemType) {
        for (E e : java.util.EnumSet.allOf(elemType)) {
            System.out.println(e);
        }
    }

    enum Color{RED,YELLOW,BLUE};
    public static void main(String[] args) {
        foo(Color.class);
    } 

}

【讨论】:

  • 简单优雅:)
【解决方案3】:

为了完整起见,JDK8 为我们提供了一种相对简洁和简洁的方式来实现这一点,而无需在 Enum 类中使用合成的 values()

给定一个简单的枚举:

private enum TestEnum {
    A,
    B,
    C
}

还有一个测试客户:

@Test
public void testAllValues() {
    System.out.println(collectAllEnumValues(TestEnum.class));
}

这将打印{A, B, C}:

public static <T extends Enum<T>> String collectAllEnumValues(Class<T> clazz) {
    return EnumSet.allOf(clazz).stream()
            .map(Enum::name)
            .collect(Collectors.joining(", " , "\"{", "}\""));
}

代码可以很容易地适应检索不同的元素或以不同的方式收集。

【讨论】:

    【解决方案4】:

    使用不安全的演员表:

    class Filter<T extends Enum<T>> {
        private List<T> availableOptions = new ArrayList<T>();
        private T selectedOption;
    
        public Filter(T selectedOption) {
            Class<T> clazz = (Class<T>) selectedOption.getClass();
            for (T option : clazz.getEnumConstants()) {
                availableOptions.add(option);
            }
        }
    }
    

    【讨论】:

    【解决方案5】:

    如果您确定构造函数Filter(T selectedOption)selectedOption 不为空。您可以使用反射。像这样。

    public class Filter<T> {
        private List<T> availableOptions = new ArrayList<T>();
        private T selectedOption;
    
        public Filter(T selectedOption) {
            this.selectedOption = selectedOption;
            for (T option : this.selectedOption.getClass().getEnumConstants()) {  // INVALID CODE
                availableOptions.add(option);
            }
        }
    }

    希望这会有所帮助。

    【讨论】:

      【解决方案6】:

      如果您将过滤器声明为

      public class Filter<T extends Iterable>
      

      然后

      import java.util.Iterator;
      
      public enum TimePeriod implements Iterable {
          ALL("All"),
          FUTURE("Future"),
          NEXT7DAYS("Next 7 Days"),
          NEXT14DAYS("Next 14 Days"),
          NEXT30DAYS("Next 30 Days"),
          PAST("Past"),
          LAST7DAYS("Last 7 Days"),
          LAST14DAYS("Last 14 Days"),
          LAST30DAYS("Last 30 Days");
      
          private final String name;
      
          private TimePeriod(String name) {
              this.name = name;
          }
      
          @Override
          public String toString() {
              return name;
          }
      
          public Iterator<TimePeriod> iterator() {
              return new Iterator<TimePeriod>() {
      
                  private int index;
      
                  @Override
                  public boolean hasNext() {
                      return index < LAST30DAYS.ordinal();
                  }
      
                  @Override
                  public TimePeriod next() {
                      switch(index++) {
                          case    0   : return        ALL;
                          case    1   : return        FUTURE;
                          case    2   : return        NEXT7DAYS;
                          case    3   : return        NEXT14DAYS;
                          case    4   : return        NEXT30DAYS;
                          case    5   : return        PAST;
                          case    6   : return        LAST7DAYS;
                          case    7   : return        LAST14DAYS;
                          case    8   : return        LAST30DAYS;
                          default: throw new IllegalStateException();
                      }
                  }
      
                  @Override
                  public void remove() {
                      throw new UnsupportedOperationException();
                  }
              };
          }
      }
      

      而且使用非常简单:

      public class Filter<T> {
          private List<T> availableOptions = new ArrayList<T>();
          private T selectedOption;
      
          public Filter(T selectedOption) {
              this.selectedOption = selectedOption;
              Iterator<TimePeriod> it = selectedOption.iterator();
              while(it.hasNext()) {
                  availableOptions.add(it.next());
              }
          }
      }
      

      【讨论】:

      • 有趣的方法。我认为这不需要声明 Class 就可以工作。但是,我宁愿不必更改所有枚举,所以我倾向于使用不同的方法。
      【解决方案7】:

      获取泛型枚举的

        protected Set<String> enum2set(Class<? extends Enum<?>> e) {
          Enum<?>[] enums = e.getEnumConstants();
          String[] names = new String[enums.length];
          for (int i = 0; i < enums.length; i++) {
            names[i] = enums[i].toString();
          }
          return new HashSet<String>(Arrays.asList(names));
        }
      

      注意上述方法中对 toString() 方法的调用。

      然后用这样的toString()方法定义枚举。

      public enum MyNameEnum {
      
        MR("John"), MRS("Anna");
      
        private String name;
      
        private MyNameEnum(String name) {
          this.name = name;
        }
      
        public String toString() {
          return this.name;
        }
      
      }
      

      【讨论】:

        【解决方案8】:

        根本问题是您需要将数组转换为列表,对吗?您可以通过使用特定类型(TimePeriod 而不是 T)和以下代码来做到这一点。

        所以使用这样的东西:

        List<TimePeriod> list = new ArrayList<TimePeriod>();
        list.addAll(Arrays.asList(sizes));
        

        现在您可以将列表传递给任何需要列表的方法。

        【讨论】:

          【解决方案9】:

          下面是一个围绕 Enum 的包装类的示例。 是不是有点奇怪 bu 是我需要的:

          public class W2UIEnum<T extends Enum<T> & Resumable> {
          
          public String id;
          public String caption;
          
          public W2UIEnum(ApplicationContext appContext, T t) {
              this.id = t.getResume();
              this.caption = I18N.singleInstance.getI18nString(t.name(), "enum_"
                      + t.getClass().getSimpleName().substring(0, 1).toLowerCase()
                      + t.getClass().getSimpleName().substring(1,
                              t.getClass().getSimpleName().length()), appContext
                      .getLocale());
          }
          
          public static <T extends Enum<T> & Resumable> List<W2UIEnum<T>> values(
                  ApplicationContext appContext, Class<T> enumType) {
              List<W2UIEnum<T>> statusList = new ArrayList<W2UIEnum<T>>();
              for (T status : enumType.getEnumConstants()) {
                  statusList.add(new W2UIEnum(appContext, status));
              }
              return statusList;
          }
          

          }

          【讨论】:

            【解决方案10】:

            我是这样做的

                protected List<String> enumToList(Class<? extends Enum<?>> e) {
                        Enum<?>[] enums = e.getEnumConstants();
                        return Arrays.asList(enums).stream()
                               .map(name -> name.toString())
                               .collect(Collectors.toList());
                    }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多