enum과 int / String 사이를 편리하게 매핑
유한 한 수의 값만 취할 수있는 변수 / 매개 변수를 다룰 때는 항상 다음 enum
과 같이 Java를 사용하려고합니다 .
public enum BonusType {
MONTHLY, YEARLY, ONE_OFF
}
내 코드 안에 머무르는 한 정상적으로 작동합니다. 그러나 종종 동일한 목적으로 일반 int
(또는 String
) 값을 사용하는 다른 코드와 인터페이스해야 하거나 데이터가 숫자 또는 문자열로 저장된 데이터베이스에서 읽고 쓸 필요가 있습니다.
이 경우 각 열거 형 값을 정수와 연결하여 두 가지 방법으로 변환 할 수있는 편리한 방법을 원합니다 (즉, "가역적 인 열거 형"이 필요합니다).
enum에서 int로 이동하는 것은 쉽습니다.
public enum BonusType {
public final int id;
BonusType(int id) {
this.id = id;
}
MONTHLY(1), YEARLY(2), ONE_OFF(3);
}
그런 다음 int 값에 액세스 할 수 있습니다 BonusType x = MONTHLY; int id = x.id;
.
그러나 int에서 enum으로 전환하는 좋은 방법은 없습니다. 이상적으로는
BonusType bt = BonusType.getById(2);
내가 얻을 수있는 유일한 해결책은 다음과 같습니다.
- 조회
BonusType.values()
"int-> enum"을 채우는 데 사용하는 조회 메소드를 열거 형 에 넣은 다음이를 캐시하여 조회에 사용합니다. 작동하지만이 방법을 내가 사용하는 각 열거 형에 똑같이 복사해야합니다. - 조회 메소드를 정적 유틸리티 클래스에 넣으십시오. 그런 다음 하나의 "조회"방법 만 필요하지만 임의의 열거 형으로 작동하려면 반사로 바이올린을 조정해야합니다.
이러한 간단한 (?) 문제는 두 방법 모두 매우 어색해 보입니다.
다른 아이디어 / 통찰력이 있습니까?
http://www.javaspecialists.co.za/archive/Issue113.html
이 솔루션은 열거 형 정의의 일부로 int 값을 사용하는 것과 유사하게 시작됩니다. 그런 다음 제네릭 기반 조회 유틸리티를 만듭니다.
public class ReverseEnumMap<V extends Enum<V> & EnumConverter> {
private Map<Byte, V> map = new HashMap<Byte, V>();
public ReverseEnumMap(Class<V> valueType) {
for (V v : valueType.getEnumConstants()) {
map.put(v.convert(), v);
}
}
public V get(byte num) {
return map.get(num);
}
}
이 솔루션은 훌륭하고 모든 리플 유형이 암시 적으로 Enum 인터페이스를 상속한다는 사실에 기반하기 때문에 '리플렉션 사용'을 필요로하지 않습니다.
enum → int
yourEnum.ordinal()
int → enum
EnumType.values()[someInt]
문자열 → 열거 형
EnumType.valueOf(yourString)
열거 형 → 문자열
yourEnum.name()
참고 :
올바르게 지적하면 ordinal()
버전마다 "불안정"할 수 있습니다. 이것이 상수를 항상 데이터베이스에 문자열로 저장하는 정확한 이유입니다. (실제로 MySql을 사용할 때 MySql 열거 형 으로 저장합니다 !)
나는 이것을 웹에서 찾았는데, 그것은 매우 도움이되고 구현하기 간단했다. 이 솔루션은 내가 만든 것이 아닙니다
http://www.ajaxonomy.com/2007/java/making-the-most-of-java-50-enum-tricks
public enum Status {
WAITING(0),
READY(1),
SKIPPED(-1),
COMPLETED(5);
private static final Map<Integer,Status> lookup
= new HashMap<Integer,Status>();
static {
for(Status s : EnumSet.allOf(Status.class))
lookup.put(s.getCode(), s);
}
private int code;
private Status(int code) {
this.code = code;
}
public int getCode() { return code; }
public static Status get(int code) {
return lookup.get(code);
}
}
이 질문에 대한 답변은 Java 8 릴리스에서 구식 인 것 같습니다.
- 데이터베이스와 같은 JVM 외부에 지속되는 경우 서 수가 불안정하므로 서수를 사용하지 마십시오.
- 키 값으로 정적 맵을 작성하는 것이 비교적 쉽습니다.
public enum AccessLevel {
PRIVATE("private", 0),
PUBLIC("public", 1),
DEFAULT("default", 2);
AccessLevel(final String name, final int value) {
this.name = name;
this.value = value;
}
private final String name;
private final int value;
public String getName() {
return name;
}
public int getValue() {
return value;
}
static final Map<String, AccessLevel> names = Arrays.stream(AccessLevel.values())
.collect(Collectors.toMap(AccessLevel::getName, Function.identity()));
static final Map<Integer, AccessLevel> values = Arrays.stream(AccessLevel.values())
.collect(Collectors.toMap(AccessLevel::getValue, Function.identity()));
public static AccessLevel fromName(final String name) {
return names.get(name);
}
public static AccessLevel fromValue(final int value) {
return values.get(value);
}
}
org.apache.commons.lang.enums.ValuedEnum;
각 Enum에 대한 상용구 코드 또는 중복 코드를 작성하지 않기 위해 ValuedEnum
대신 Apache Commons Lang을 사용했습니다.
정의 :
public class NRPEPacketType extends ValuedEnum {
public static final NRPEPacketType TYPE_QUERY = new NRPEPacketType( "TYPE_QUERY", 1);
public static final NRPEPacketType TYPE_RESPONSE = new NRPEPacketType( "TYPE_RESPONSE", 2);
protected NRPEPacketType(String name, int value) {
super(name, value);
}
}
용법:
int-> ValuedEnum :
NRPEPacketType packetType =
(NRPEPacketType) EnumUtils.getEnum(NRPEPacketType.class, 1);
아마도 다음과 같은 것을 사용할 수 있습니다
interface EnumWithId {
public int getId();
}
enum Foo implements EnumWithId {
...
}
유틸리티 클래스에 반영해야 할 필요성이 줄어 듭니다.
이 코드에서는 영구적이고 강렬한 검색을 위해 메모리 또는 프로세스를 사용하고 변환기 배열을 인덱스로 사용하여 메모리를 선택합니다. 도움이 되길 바랍니다.
public enum Test{
VALUE_ONE(101, "Im value one"),
VALUE_TWO(215, "Im value two");
private final int number;
private final byte[] desc;
private final static int[] converter = new int[216];
static{
Test[] st = values();
for(int i=0;i<st.length;i++){
cv[st[i].number]=i;
}
}
Test(int value, byte[] description) {
this.number = value;
this.desc = description;
}
public int value() {
return this.number;
}
public byte[] description(){
return this.desc;
}
public static String description(int value) {
return values()[converter[rps]].desc;
}
public static Test fromValue(int value){
return values()[converter[rps]];
}
}
인터페이스를 사용하여 누가 보스인지 보여줍니다.
public interface SleskeEnum {
int id();
SleskeEnum[] getValues();
}
public enum BonusType implements SleskeEnum {
MONTHLY(1), YEARLY(2), ONE_OFF(3);
public final int id;
BonusType(int id) {
this.id = id;
}
public SleskeEnum[] getValues() {
return values();
}
public int id() { return id; }
}
public class Utils {
public static SleskeEnum getById(SleskeEnum type, int id) {
for(SleskeEnum t : type.getValues())
if(t.id() == id) return t;
throw new IllegalArgumentException("BonusType does not accept id " + id);
}
public static void main(String[] args) {
BonusType shouldBeMonthly = (BonusType)getById(BonusType.MONTHLY,1);
System.out.println(shouldBeMonthly == BonusType.MONTHLY);
BonusType shouldBeMonthly2 = (BonusType)getById(BonusType.MONTHLY,1);
System.out.println(shouldBeMonthly2 == BonusType.YEARLY);
BonusType shouldBeYearly = (BonusType)getById(BonusType.MONTHLY,2);
System.out.println(shouldBeYearly == BonusType.YEARLY);
BonusType shouldBeOneOff = (BonusType)getById(BonusType.MONTHLY,3);
System.out.println(shouldBeOneOff == BonusType.ONE_OFF);
BonusType shouldException = (BonusType)getById(BonusType.MONTHLY,4);
}
}
그리고 결과 :
C:\Documents and Settings\user\My Documents>java Utils
true
false
true
true
Exception in thread "main" java.lang.IllegalArgumentException: BonusType does not accept id 4
at Utils.getById(Utils.java:6)
at Utils.main(Utils.java:23)
C:\Documents and Settings\user\My Documents>
모두 .ordinal()
와 values()[i]
그들이 열거의 순서에 의존하기 때문에 불안정하다. 따라서 열거 형의 순서를 변경하거나 일부를 추가 / 삭제하면 프로그램이 중단됩니다.
다음은 enum과 int를 간단하고 효과적으로 매핑하는 방법입니다.
public enum Action {
ROTATE_RIGHT(0), ROTATE_LEFT(1), RIGHT(2), LEFT(3), UP(4), DOWN(5);
public final int id;
Action(int id) {
this.id = id;
}
public static Action get(int id){
for (Action a: Action.values()) {
if (a.id == id)
return a;
}
throw new IllegalArgumentException("Invalid id");
}
}
문자열에 적용하는 것은 어렵지 않습니다.
리버스 Enum의 매우 깨끗한 사용 예
1 단계interface
EnumConverter 정의
public interface EnumConverter <E extends Enum<E> & EnumConverter<E>> {
public String convert();
E convert(String pKey);
}
2 단계
클래스 이름 만들기 ReverseEnumMap
import java.util.HashMap;
import java.util.Map;
public class ReverseEnumMap<V extends Enum<V> & EnumConverter<V>> {
private Map<String, V> map = new HashMap<String, V>();
public ReverseEnumMap(Class<V> valueType) {
for (V v : valueType.getEnumConstants()) {
map.put(v.convert(), v);
}
}
public V get(String pKey) {
return map.get(pKey);
}
}
3 단계
당신로 이동 Enum
클래스와 implement
그것과 EnumConverter<ContentType>
물론 재정의 인터페이스 방법. 정적 ReverseEnumMap도 초기화해야합니다.
public enum ContentType implements EnumConverter<ContentType> {
VIDEO("Video"), GAME("Game"), TEST("Test"), IMAGE("Image");
private static ReverseEnumMap<ContentType> map = new ReverseEnumMap<ContentType>(ContentType.class);
private final String mName;
ContentType(String pName) {
this.mName = pName;
}
String value() {
return this.mName;
}
@Override
public String convert() {
return this.mName;
}
@Override
public ContentType convert(String pKey) {
return map.get(pKey);
}
}
4 단계
이제 Communication
클래스 파일을 만들고 Enum
to String
및 String
to 로 변환하는 새로운 메소드를 호출하십시오 Enum
. 설명을 위해 주요 방법을 넣었습니다.
public class Communication<E extends Enum<E> & EnumConverter<E>> {
private final E enumSample;
public Communication(E enumSample) {
this.enumSample = enumSample;
}
public String resolveEnumToStringValue(E e) {
return e.convert();
}
public E resolveStringEnumConstant(String pName) {
return enumSample.convert(pName);
}
//Should not put main method here... just for explanation purpose.
public static void main(String... are) {
Communication<ContentType> comm = new Communication<ContentType>(ContentType.GAME);
comm.resolveEnumToStringValue(ContentType.GAME); //return Game
comm.resolveStringEnumConstant("Game"); //return GAME (Enum)
}
}
Java에서 동일한 지 확실하지 않지만 C의 열거 형은 자동으로 정수에 매핑되므로 형식이나 정수를 사용하여 액세스 할 수 있습니다. 정수로 아직 액세스하려고 했습니까?
정말 좋은 질문 :-) 나는 얼마 전에 Ferguson과 비슷한 솔루션을 사용했습니다. 디 컴파일 된 열거 형은 다음과 같습니다.
final class BonusType extends Enum
{
private BonusType(String s, int i, int id)
{
super(s, i);
this.id = id;
}
public static BonusType[] values()
{
BonusType abonustype[];
int i;
BonusType abonustype1[];
System.arraycopy(abonustype = ENUM$VALUES, 0, abonustype1 = new BonusType[i = abonustype.length], 0, i);
return abonustype1;
}
public static BonusType valueOf(String s)
{
return (BonusType)Enum.valueOf(BonusType, s);
}
public static final BonusType MONTHLY;
public static final BonusType YEARLY;
public static final BonusType ONE_OFF;
public final int id;
private static final BonusType ENUM$VALUES[];
static
{
MONTHLY = new BonusType("MONTHLY", 0, 1);
YEARLY = new BonusType("YEARLY", 1, 2);
ONE_OFF = new BonusType("ONE_OFF", 2, 3);
ENUM$VALUES = (new BonusType[] {
MONTHLY, YEARLY, ONE_OFF
});
}
}
왜 이것이 ordinal()
불안정한 지 알 수 있습니다. 그것은이다 i
에서 super(s, i);
. 또한 이미 열거 한 것보다 더 우아한 솔루션을 생각할 수 있다고 비관적입니다. 모든 열거 형은 최종 클래스로서의 클래스입니다.
완성도를 높이기 위해 다음은 모든 열거 형 유형에서 인덱스별로 열거 형 값을 검색하는 일반적인 방법입니다. 내 의도는 메소드를 Enum.valueOf (Class, String) 처럼 보이게하고 느끼게하는 것이 었습니다 . Fyi, 나는이 방법을 here 에서 복사했습니다 .
색인 관련 문제 (이미 자세히 설명되어 있음)가 여전히 적용됩니다.
/**
* Returns the {@link Enum} instance for a given ordinal.
* This method is the index based alternative
* to {@link Enum#valueOf(Class, String)}, which
* requires the name of an instance.
*
* @param <E> the enum type
* @param type the enum class object
* @param ordinal the index of the enum instance
* @throws IndexOutOfBoundsException if ordinal < 0 || ordinal >= enums.length
* @return the enum instance with the given ordinal
*/
public static <E extends Enum<E>> E valueOf(Class<E> type, int ordinal) {
Preconditions.checkNotNull(type, "Type");
final E[] enums = type.getEnumConstants();
Preconditions.checkElementIndex(ordinal, enums.length, "ordinal");
return enums[ordinal];
}
Int -->String :
public enum Country {
US("US",0),
UK("UK",2),
DE("DE",1);
private static Map<Integer, String> domainToCountryMapping;
private String country;
private int domain;
private Country(String country,int domain){
this.country=country.toUpperCase();
this.domain=domain;
}
public String getCountry(){
return country;
}
public static String getCountry(String domain) {
if (domainToCountryMapping == null) {
initMapping();
}
if(domainToCountryMapping.get(domain)!=null){
return domainToCountryMapping.get(domain);
}else{
return "US";
}
}
private static void initMapping() {
domainToCountryMapping = new HashMap<Integer, String>();
for (Country s : values()) {
domainToCountryMapping.put(s.domain, s.country);
}
}
일반적인 접근법을 사용하고 싶었 기 때문에 다른 것이 필요했습니다. 바이트 배열과 열거 형을 읽고 있습니다. 이것은 내가 생각해 낸 곳입니다.
public interface EnumConverter {
public Number convert();
}
public class ByteArrayConverter {
@SuppressWarnings("unchecked")
public static Enum<?> convertToEnum(byte[] values, Class<?> fieldType, NumberSystem numberSystem) throws InvalidDataException {
if (values == null || values.length == 0) {
final String message = "The values parameter must contain the value";
throw new IllegalArgumentException(message);
}
if (!dtoFieldType.isEnum()) {
final String message = "dtoFieldType must be an Enum.";
throw new IllegalArgumentException(message);
}
if (!EnumConverter.class.isAssignableFrom(fieldType)) {
final String message = "fieldType must implement the EnumConverter interface.";
throw new IllegalArgumentException(message);
}
Enum<?> result = null;
Integer enumValue = (Integer) convertToType(values, Integer.class, numberSystem); // Our enum's use Integer or Byte for the value field.
for (Object enumConstant : fieldType.getEnumConstants()) {
Number ev = ((EnumConverter) enumConstant).convert();
if (enumValue.equals(ev)) {
result = (Enum<?>) enumConstant;
break;
}
}
if (result == null) {
throw new EnumConstantNotPresentException((Class<? extends Enum>) fieldType, enumValue.toString());
}
return result;
}
public static byte[] convertEnumToBytes(Enum<?> value, int requiredLength, NumberSystem numberSystem) throws InvalidDataException {
if (!(value instanceof EnumConverter)) {
final String message = "dtoFieldType must implement the EnumConverter interface.";
throw new IllegalArgumentException(message);
}
Number enumValue = ((EnumConverter) value).convert();
byte[] result = convertToBytes(enumValue, requiredLength, numberSystem);
return result;
}
public static Object convertToType(byte[] values, Class<?> type, NumberSystem numberSystem) throws InvalidDataException {
// some logic to convert the byte array supplied by the values param to an Object.
}
public static byte[] convertToBytes(Object value, int requiredLength, NumberSystem numberSystem) throws InvalidDataException {
// some logic to convert the Object supplied by the'value' param to a byte array.
}
}
열거 형의 예 :
public enum EnumIntegerMock implements EnumConverter {
VALUE0(0), VALUE1(1), VALUE2(2);
private final int value;
private EnumIntegerMock(int value) {
this.value = value;
}
public Integer convert() {
return value;
}
}
public enum EnumByteMock implements EnumConverter {
VALUE0(0), VALUE1(1), VALUE2(2);
private final byte value;
private EnumByteMock(int value) {
this.value = (byte) value;
}
public Byte convert() {
return value;
}
}
수락 된 답변이 자체 포함되어 있지 않기 때문에 :
지원 코드 :
public interface EnumWithCode<E extends Enum<E> & EnumWithCode<E>> {
public Integer getCode();
E fromCode(Integer code);
}
public class EnumWithCodeMap<V extends Enum<V> & EnumWithCode<V>> {
private final HashMap<Integer, V> _map = new HashMap<Integer, V>();
public EnumWithCodeMap(Class<V> valueType) {
for( V v : valueType.getEnumConstants() )
_map.put(v.getCode(), v);
}
public V get(Integer num) {
return _map.get(num);
}
}
사용 예 :
public enum State implements EnumWithCode<State> {
NOT_STARTED(0), STARTED(1), ENDED(2);
private static final EnumWithCodeMap<State> map = new EnumWithCodeMap<State>(
State.class);
private final int code;
private State(int code) {
this.code = code;
}
@Override
public Integer getCode() {
return code;
}
@Override
public State fromCode(Integer code) {
return map.get(code);
}
}
주어진:
공개 열거 형 BonusType {MONTHLY (0), YEARLY (1), ONE_OFF (2)}
BonusType 보너스 = 매년;
System.out.println (bonus.Ordinal () + ":"+ 보너스)
산출 : 1 : YEARLY
참고 URL : https://stackoverflow.com/questions/5021246/conveniently-map-between-enum-and-int-string
'program tip' 카테고리의 다른 글
httpClient.GetAsync를 사용할 때 헤더 추가 (0) | 2020.08.06 |
---|---|
Xcode 4에서 iPhone 앱 이름 변경 (0) | 2020.08.06 |
JavaScript로 메타 태그에서 정보를 얻으려면 어떻게해야합니까? (0) | 2020.08.06 |
쉼표로 할당해도 작동합니까? (0) | 2020.08.05 |
Django 템플릿에서 중첩 for 루프로 가장 바깥 쪽 forloop.counter에 액세스하는 방법은 무엇입니까? (0) | 2020.08.05 |