답변:
서수를 열거 형 represantation으로 변환하려면 다음을 수행하십시오.
ReportTypeEnum value = ReportTypeEnum.values()[ordinal];
배열 범위를 확인하십시오.
호출 할 때마다 values()
새로 복제 된 배열 을 반환하므로 성능에 부정적인 영향을 줄 수 있습니다. 배열이 자주 호출되는 경우 배열을 캐시 할 수 있습니다.
이 답변은 댓글 안에 제공된 피드백을 포함하도록 편집되었습니다
이것은 거의 확실히 나쁜 생각 입니다. 물론 서 수가 사실상 유지되지 않는 경우 (예 : 누군가가 URL을 북마크에 추가했기 때문에) enum
이는 향후 순서를 항상 유지해야한다는 것을 의미합니다 . 이는 코드 관리자에게 명확하지 않을 수 있습니다.
대신 인코딩을 enum
사용하고 myEnumValue.name()
(를 통해 디코딩 ReportTypeEnum.valueOf(s)
) 왜 안 됩니까?
value
시작하거나 올바른 알파벳 / 논리 위치 에을 추가하는 것보다 훨씬 적다고 생각합니다 . (논리적으로 나는 예를 들어 TimeUnit
값이 논리적 인 위치를 의미 함 )
values()
많이 사용할 예정이라면 :
enum Suit {
Hearts, Diamonds, Spades, Clubs;
public static final Suit values[] = values();
}
한편 where.java :
Suit suit = Suit.values[ordinal];
배열 경계를 염두에 두십시오.
Suit.values[0] = Suit.Diamonds;
코드의 어딘가를 막지는 않습니다 . 이상적으로는 결코 발생 하지 않지만 변경 가능한 필드를 노출시키지 않는 전반적인 원칙은 여전히 유효합니다. 이 방법의 경우 Collections.unmodifiableList
대신 등을 사용 하는 것이 좋습니다.
Suit values[]
직접 또는 간접적으로 노출되지는 않습니다 (어떻게 언급 되었는가 getValues()
), 나는 ordinal
인수가 어떻게 전달되고 Suit
표현을 반환 해야하는지 공개 메소드로 해결합니다 Suit values[]
. 여기서 요점은 (처음부터 질문의 타일) 열거 형 서수에서 열거 형을 만들었습니다
나는 서수를 사용하는 것이 아마도 나쁜 생각이라는 대부분의 사람들에게 동의합니다. 나는 일반적으로 열거 형에 DB 값을 취할 수있는 개인 생성자를 제공하여 fromDbValue
Jan의 답변과 비슷한 정적 함수 를 생성 하여이 문제를 해결합니다 .
public enum ReportTypeEnum {
R1(1),
R2(2),
R3(3),
R4(4),
R5(5),
R6(6),
R7(7),
R8(8);
private static Logger log = LoggerFactory.getLogger(ReportEnumType.class);
private static Map<Integer, ReportTypeEnum> lookup;
private Integer dbValue;
private ReportTypeEnum(Integer dbValue) {
this.dbValue = dbValue;
}
static {
try {
ReportTypeEnum[] vals = ReportTypeEnum.values();
lookup = new HashMap<Integer, ReportTypeEnum>(vals.length);
for (ReportTypeEnum rpt: vals)
lookup.put(rpt.getDbValue(), rpt);
}
catch (Exception e) {
// Careful, if any exception is thrown out of a static block, the class
// won't be initialized
log.error("Unexpected exception initializing " + ReportTypeEnum.class, e);
}
}
public static ReportTypeEnum fromDbValue(Integer dbValue) {
return lookup.get(dbValue);
}
public Integer getDbValue() {
return this.dbValue;
}
}
이제 조회를 변경하지 않고 순서를 변경할 수 있으며 그 반대도 마찬가지입니다.
당신은 할 수 정적 조회 테이블을 사용합니다 :
public enum Suit {
spades, hearts, diamonds, clubs;
private static final Map<Integer, Suit> lookup = new HashMap<Integer, Suit>();
static{
int ordinal = 0;
for (Suit suit : EnumSet.allOf(Suit.class)) {
lookup.put(ordinal, suit);
ordinal+= 1;
}
}
public Suit fromOrdinal(int ordinal) {
return lookup.get(ordinal);
}
}
0...(n-1)
인 경우 배열은 코드가 적고 읽기 쉽습니다. 성능 향상은 보너스 일뿐입니다. private static final Suit[] VALUES = values();
그리고 public Suit fromOrdinal(int ordinal) { return VALUES[ordinal]; }
. 추가 이점 : 자동으로 null을 반환하지 않고 잘못된 서수에서 즉시 충돌합니다. (항상 이점은 아니지만 종종.)
이것이 내가 사용하는 것입니다. 위의 간단한 솔루션보다 훨씬 덜 "효율적"이라고 주장하지 않습니다. 위의 솔루션에서 유효하지 않은 서수 값을 사용하는 경우 "ArrayIndexOutOfBounds"보다 훨씬 명확한 예외 메시지를 제공합니다.
EnumSet javadoc이 반복자가 요소를 자연 순서로 반환하도록 지정한다는 사실을 이용합니다. 정확하지 않은 주장이 있습니다.
JUnit4 테스트는 사용 방법을 보여줍니다.
/**
* convert ordinal to Enum
* @param clzz may not be null
* @param ordinal
* @return e with e.ordinal( ) == ordinal
* @throws IllegalArgumentException if ordinal out of range
*/
public static <E extends Enum<E> > E lookupEnum(Class<E> clzz, int ordinal) {
EnumSet<E> set = EnumSet.allOf(clzz);
if (ordinal < set.size()) {
Iterator<E> iter = set.iterator();
for (int i = 0; i < ordinal; i++) {
iter.next();
}
E rval = iter.next();
assert(rval.ordinal() == ordinal);
return rval;
}
throw new IllegalArgumentException("Invalid value " + ordinal + " for " + clzz.getName( ) + ", must be < " + set.size());
}
@Test
public void lookupTest( ) {
java.util.concurrent.TimeUnit tu = lookupEnum(TimeUnit.class, 3);
System.out.println(tu);
}
이것이 Proguard를 사용하여 Android에서 수행하는 작업입니다.
public enum SomeStatus {
UNINITIALIZED, STATUS_1, RESERVED_1, STATUS_2, RESERVED_2, STATUS_3;//do not change order
private static SomeStatus[] values = null;
public static SomeStatus fromInteger(int i) {
if(SomeStatus.values == null) {
SomeStatus.values = SomeStatus.values();
}
if (i < 0) return SomeStatus.values[0];
if (i >= SomeStatus.values.length) return SomeStatus.values[0];
return SomeStatus.values[i];
}
}
짧고 Proguard에서 예외가 발생할 염려가 없습니다.
public enum Suit implements java.io.Serializable, Comparable<Suit>{
spades, hearts, diamonds, clubs;
private static final Suit [] lookup = Suit.values();
public Suit fromOrdinal(int ordinal) {
if(ordinal< 1 || ordinal> 3) return null;
return lookup[value-1];
}
}
테스트 클래스
public class MainTest {
public static void main(String[] args) {
Suit d3 = Suit.diamonds;
Suit d3Test = Suit.fromOrdinal(2);
if(d3.equals(d3Test)){
System.out.println("Susses");
}else System.out.println("Fails");
}
}
더 효율적인 코드가 있다면 우리와 공유해 주셔서 감사합니다. 내 열거 형은 거대하고 끊임없이 수천 번 불립니다.
따라서 한 가지 방법은 ExampleEnum valueOfOrdinal = ExampleEnum.values()[ordinal];
어느 것이 효과가 있으며 이전에 언급했듯이 ExampleEnum.values()
모든 호출에 대해 새로운 복제 된 배열을 반환합니다. 불필요하게 비쌀 수 있습니다. 우리는 배열을 캐싱함으로써 이것을 해결할 수 있습니다.ExampleEnum[] values = values()
. 캐시 된 어레이를 수정하는 것도 "위험"합니다. 누군가 쓸 수 ExampleEnum.values[0] = ExampleEnum.type2;
있으므로 여분의 복사를 수행하지 않는 접근 자 메소드를 사용하여 비공개로 만들 것입니다.
private enum ExampleEnum{
type0, type1, type2, type3;
private static final ExampleEnum[] values = values();
public static ExampleEnum value(int ord) {
return values[ord];
}
}
ExampleEnum.value(ordinal)
관련된 enum 값을 얻는 데 사용 합니다.ordinal
모든 열거 형에는 name ()이 있으며, 이는 열거 형 멤버의 이름을 가진 문자열을 제공합니다.
주어진 enum Suit{Heart, Spade, Club, Diamond}
, Suit.Heart.name()
줄 것이다Heart
.
모든 열거 형에는 valueOf()
역 연산을 수행하기 위해 열거 형과 문자열을 사용 메소드 있습니다.
Enum.valueOf(Suit.class, "Heart")
을 반환합니다 Suit.Heart
.
누구나 서수를 사용하는 이유는 저 밖에 있습니다. 다른 개발자가 일부 코드가 서수 값에 의존한다는 것을 알지 못하기 때문에 열거 형 멤버가 변경되면 나노 초가 빠를 수 있지만 안전하지는 않습니다 (특히 질문에 인용 된 JSP 페이지에서 네트워크 및 데이터베이스 오버 헤드가 완전히 지배합니다) 문자열에 정수를 사용하지 않는 시간).