[java] Java 제네릭을 사용하여 열거 형 값 반복

제네릭을 사용하는 동안 열거 형 값을 반복하는 방법을 찾으려고합니다. 이 작업을 수행하는 방법 또는 가능한지 확실하지 않습니다.

다음 코드는 내가 원하는 것을 보여줍니다. 코드 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<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에 null이 아닌 값이 있는지 확인할 수 있다면 이것은 잘 작동합니다. 불행히도 내 사용 사례에서는 public Filter () no-arg 생성자 가 있기 때문에이 값은 종종 null 입니다. 이것은 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);
        }
    }
}

생성자에 추가 클래스 매개 변수가 필요하지 않고이를 수행하는 방법에 대한 아이디어가 있습니까?



답변

이것은 참으로 어려운 문제입니다. 해야 할 일 중 하나는 열거 형을 사용하고 있음을 Java에 알리는 것입니다. 이것은 제네릭에 대한 Enum 클래스를 확장한다는 것을 나타냅니다. 그러나이 클래스에는 values ​​() 함수가 없습니다. 따라서 값을 얻을 수있는 수업을 들어야합니다.

다음 예는 문제 해결에 도움이됩니다.

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


답변

또 다른 옵션은 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);
    }

}


답변

완전성을 위해 JDK8은 values()Enum 클래스 에서 합성을 사용할 필요없이이를 달성 할 수있는 비교적 깨끗하고 간결한 방법을 제공합니다 .

간단한 열거 형이 주어지면 :

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(", " , "\"{", "}\""));
}

다른 요소를 검색하거나 다른 방식으로 수집하도록 코드를 사소하게 조정할 수 있습니다.


답변

안전하지 않은 캐스트 사용 :

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생성자 Filter(T selectedOption)가 null이 아닌 것이 확실한 경우 . 반사를 사용할 수 있습니다. 이렇게.

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

도움이 되었기를 바랍니다.


답변

일반 열거 의 을 가져 오려면 다음 을 수행하십시오.

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

}


답변

근본 문제는 배열을 목록으로 변환해야한다는 것입니다. 그렇죠? 특정 유형 (T 대신 TimePeriod)과 다음 코드를 사용하여이를 수행 할 수 있습니다.

따라서 다음과 같이 사용하십시오.

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

이제 목록을 원하는 모든 메소드에 목록을 전달할 수 있습니다.