Podczas pracy ze zmiennymi / parametrami, które mogą przyjmować tylko skończoną liczbę wartości, staram się zawsze używać języka Java enum
, tak jak w
public enum BonusType {
MONTHLY, YEARLY, ONE_OFF
}
Tak długo, jak pozostaję w swoim kodzie, działa dobrze. Jednak często muszę łączyć się z innym kodem, który używa zwykłych int
(lub String
) wartości do tego samego celu, lub muszę czytać / zapisywać z / do bazy danych, w której dane są przechowywane jako liczba lub ciąg.
W takim przypadku chciałbym mieć wygodny sposób powiązania każdej wartości wyliczenia z liczbą całkowitą, tak aby można było konwertować w obie strony (innymi słowy, potrzebuję „odwracalnego wyliczenia”).
Przejście od enum do int jest łatwe:
public enum BonusType {
public final int id;
BonusType(int id) {
this.id = id;
}
MONTHLY(1), YEARLY(2), ONE_OFF(3);
}
Wtedy mogę uzyskać dostęp do wartości int jako BonusType x = MONTHLY; int id = x.id;
.
Jednak nie widzę fajnego sposobu na odwrócenie, tj. Przejście z int do enum. Idealnie coś takiego
BonusType bt = BonusType.getById(2);
Jedyne rozwiązania, jakie mogłem wymyślić, to:
- Umieść metodę wyszukiwania w wyliczeniu, która
BonusType.values()
wypełnia mapę „int -> enum”, a następnie buforuje ją i używa do wyszukiwania. Zadziałałoby, ale musiałbym skopiować tę metodę identycznie do każdego wyliczenia, którego używam :-(. - Umieść metodę wyszukiwania w statycznej klasie narzędziowej. Wtedy potrzebowałbym tylko jednej metody „wyszukiwania”, ale musiałbym majstrować przy odbiciu, aby działał dla dowolnego wyliczenia.
Obie metody wydają się strasznie niewygodne w przypadku tak prostego (?) Problemu.
Jakieś inne pomysły / spostrzeżenia?
źródło
ordinal()
.ordinal()
), czy też są one ustalane przez siły zewnętrzne?Odpowiedzi:
http://www.javaspecialists.co.za/archive/Issue113.html
Rozwiązanie zaczyna się podobnie do twojego z wartością int jako częścią definicji wyliczenia. Następnie tworzy narzędzie wyszukiwania oparte na generycznych:
To rozwiązanie jest przyjemne i nie wymaga „majstrowania przy odbiciu”, ponieważ jest oparte na fakcie, że wszystkie typy wyliczeniowe domyślnie dziedziczą interfejs Enum.
źródło
Number
zamiastByte
, ponieważ moja wartość zapasowa może być większa.enum → int
int → enum
String → enum
enum → String
Na marginesie:
jak słusznie zauważyłeś, plik
ordinal()
może być „niestabilny” z wersji na wersję. To jest dokładny powód, dla którego zawsze przechowuję stałe jako ciągi w moich bazach danych. (Właściwie podczas korzystania z MySql przechowuję je jako wyliczenia MySql !)źródło
BonusType.valueOf("MONTHLY")
)ordinal()
wydaje mi się problematyczne, ponieważ może się zepsuć, gdy lista wartości wyliczeniowych zostanie zmieniona lub wartość zostanie usunięta. Jest to również praktyczne tylko wtedy, gdy wartości int są równe 0 ... n (co, jak często, nie ma miejsca).values()
tablicy będzie działać tylko wtedy, gdy wszystkie wartości są indeksowane za 0 id i deklarowane są w porządku. (Testowałem to, aby sprawdzić, jeśli deklarująFOO(0), BAR(2), BAZ(1);
, żevalues[1] == BAR
ivalues[2] == BAZ
pomimo identyfikatorów wydanych w.)double
).Znalazłem to w sieci, było bardzo pomocne i łatwe do wdrożenia. To rozwiązanie NIE zostało wykonane przeze mnie
http://www.ajaxonomy.com/2007/java/making-the-most-of-java-50-enum-tricks
}
źródło
Wydaje się, że odpowiedzi na to pytanie są nieaktualne w wydaniu Java 8.
źródło
Collectors.toMap()
byćFunctions.identity()
zamiastnull
?org.apache.commons.lang.enums.ValuedEnum;
Aby zaoszczędzić mi pisania wielu standardowych kodów lub powielania kodu dla każdego Enum, użyłem
ValuedEnum
zamiast tego Apache Commons Lang .Definicja :
Stosowanie:
int -> ValuedEnum:
źródło
Możesz użyć czegoś takiego
Zmniejszyłoby to potrzebę refleksji w twojej klasie użytkowej.
źródło
W tym kodzie, do stałego i intensywnego wyszukiwania, mam pamięć lub proces do użycia i wybieram pamięć z tablicą konwertera jako indeksem. Mam nadzieję, że to pomocne
źródło
Użyj interfejsu, aby pokazać, kto tu rządzi.
A wynik:
źródło
Zarówno, jak
.ordinal()
ivalues()[i]
są niestabilne, ponieważ są zależne od kolejności wyliczeń. Dlatego jeśli zmienisz kolejność wyliczeń lub dodasz / usuniesz część programu, program się zepsuje.Oto prosta, ale skuteczna metoda mapowania między enum i int.
Nałożenie go na struny nie powinno być trudne.
źródło
Krok 1 Zdefiniuj
interface
EnumConverterKrok 2
Utwórz nazwę klasy ReverseEnumMap
Krok 3
Idź do Ciebie
Enum
klasie, aimplement
to zeEnumConverter<ContentType>
i przesłanianie metod interfejsu kursu. Musisz także zainicjować statyczną mapę ReverseEnumMap.Krok 4
Teraz utwórz
Communication
plik klasy i wywołaj nową metodę, aby przekonwertowaćEnum
naString
iString
naEnum
. Właśnie przedstawiłem główną metodę w celu wyjaśnienia.Kliknij, aby uzyskać pełne wyjaśnienie
źródło
ContentType convert(String pKey)
statystyka, co eliminuje potrzebęCommunication
zajęć i bardziej mi się podobało. +1Nie jestem pewien, czy jest to to samo w Javie, ale typy wyliczeniowe w C są również automatycznie mapowane na liczby całkowite, więc możesz użyć typu lub liczby całkowitej, aby uzyskać do niego dostęp. Czy próbowałeś już po prostu uzyskać do niego dostęp za pomocą liczby całkowitej?
źródło
.ordinal()
metody. (W drugą stronę, użyjBonusType.values()[i]
.) Ale w powyższym przykładzie indeksy tutaj i wartości zewnętrzne nie pokrywają się.Naprawdę świetne pytanie :-) Jakiś czas temu korzystałem z rozwiązania podobnego do pana Ferguson. Nasze zdekompilowane wyliczenie wygląda następująco:
Widząc to, widać, dlaczego
ordinal()
jest niestabilny. To jesti
wsuper(s, i);
. Jestem również pesymistą, że można wymyślić bardziej eleganckie rozwiązanie niż te, które już wymieniłeś. Przecież wyliczenia są klasami jak wszystkie klasy końcowe.źródło
Ze względu na kompletność, oto ogólne podejście do pobierania wartości wyliczenia według indeksu z dowolnego typu wyliczenia. Moim zamiarem było, aby metoda wyglądała i działała jak Enum.valueOf (Class, String) . Fyi, skopiowałem stąd tę metodę .
Nadal obowiązują kwestie związane z indeksem (już szczegółowo omówione tutaj).
źródło
MyEnumType.values()
- nie ma potrzeby stosowania statycznej metody pomocniczej.źródło
Potrzebowałem czegoś innego, ponieważ chciałem zastosować podejście ogólne. Czytam wyliczenie do iz tablic bajtowych. Oto, co wymyśliłem:
Przykład wyliczeń:
}
źródło
Tylko dlatego, że zaakceptowana odpowiedź nie jest samodzielna:
Kod pomocniczy:
Przykład użycia:
źródło
dany:
publiczne wyliczenie BonusType {MONTHLY (0), YEARLY (1), ONE_OFF (2)}
BonusType = YEARLY;
System.out.println (bonus.Ordinal () + ":" + bonus)
Wyjście: 1: ROCZNIE
źródło
Jeśli masz samochód klasy
Właściwość Color jest klasą
I chcesz przekonwertować Color na Enum
Po prostu dodaj metodę w klasie Color, aby przekonwertować Color na ColorEnum
a wewnątrz ColorEnum implementuje metodę getById ()
Teraz możesz użyć mapy klas
źródło