Wyliczenia nie muszą tylko reprezentować zestawów pasywnych (np. Kolorów). Mogą one stanowić więcej obiektów złożonych z funkcjonalnością, a więc jesteś następnie prawdopodobnie chcesz dodać dodatkowej funkcjonalności do nich - na przykład może mieć interfejsy, takie jak Printable, Reportableitd. I komponenty, które obsługują te.
Oto jeden przykład (podobny / lepszy można znaleźć w Effective Java 2nd Edition):
publicinterfaceOperator{int apply (int a,int b);}publicenumSimpleOperatorsimplementsOperator{
PLUS {int apply(int a,int b){return a + b;}},
MINUS {int apply(int a,int b){return a - b;}};}publicenumComplexOperatorsimplementsOperator{// can't think of an example right now :-/}
Teraz, aby uzyskać listę operatorów Simple + Complex:
Po raz pierwszy zobaczyłem tę składnię Enum (z nawiasami klamrowymi po członkach), a programuję w Javie od 6 lat. TIL
jrahhali
23
ComparablePrzykład podany przez kilka osób tu jest nie tak, skoro Enumjuż narzędzia, które. Nie możesz tego nawet przesłonić.
Lepszym przykładem jest interfejs definiujący, powiedzmy, typ danych. Możesz mieć wyliczenie do implementacji prostych typów i mieć normalne klasy do implementowania skomplikowanych typów:
interfaceDataType{// methods here}enumSimpleDataTypeimplementsDataType{
INTEGER, STRING;// implement methods}classIdentifierDataTypeimplementsDataType{// implement interface and maybe add more specific methods}
Tak, dziwne !! Enum już implementuje interfejs porównywalny i nie pozwala na zastąpienie. Poszukałem kodu źródłowego Java dla klasy enum i nie mogłem znaleźć implementacji CompareTo. Czy ktoś może mi powiedzieć, co jest porównywane w metodzie porównywania ENUM?
AKh
2
@AKh porównuje liczby porządkowe, co oznacza, że porządek naturalny to kolejność stałych wyliczeniowych w pliku źródłowym.
Jorn
Wyliczenia wroga są ostateczne, więc porównanie następuje z ==, prawda?
djangofan
@djangofan tak.
Jorn
17
Jest taki przypadek, z którego często korzystam. Mam IdUtilklasę ze statycznymi metodami do pracy z obiektami implementującymi bardzo prosty Identifiableinterfejs:
publicinterfaceIdentifiable<K>{
K getId();}publicabstractclassIdUtil{publicstatic<T extendsEnum<T>&Identifiable<S>, S> T get(Class<T> type, S id){for(T t : type.getEnumConstants()){if(Util.equals(t.getId(), id)){return t;}}returnnull;}publicstatic<T extendsEnum<T>&Identifiable<S>, S extendsComparable<?super S>>List<T> getLower(T en){List<T> list =newArrayList<>();for(T t : en.getDeclaringClass().getEnumConstants()){if(t.getId().compareTo(en.getId())<0){
list.add(t);}}return list;}}
Ponieważ Enums mogą implementować interfejsy, można ich używać do ścisłego egzekwowania wzorca singletonu. Próba stworzenia standardowej klasy singletonu pozwala ...
za możliwość wykorzystania technik refleksyjnych do ujawnienia prywatnych metod jako publicznych
do dziedziczenia po singletonie i zastępowania metod singletona czymś innym
Wyliczenia jako singletony pomagają zapobiegać tym problemom bezpieczeństwa. To mógł być jeden z głównych powodów, dla których Enums działał jak klasy i implementował interfejsy. Tylko zgadnij.
for inheriting from your singleton and overriding your singleton's methods with something else. możesz po prostu użyć a, final classaby temu zapobiec
Dylanthepiguy 19.04.17
10
Jest to wymagane do rozszerzenia - jeśli ktoś używa API, które opracowałeś, wyliczenia, które definiujesz, są statyczne; nie można ich dodawać ani modyfikować. Jeśli jednak zezwolisz mu na implementację interfejsu, osoba korzystająca z interfejsu API może opracować własne wyliczenie za pomocą tego samego interfejsu. Następnie możesz zarejestrować to wyliczenie za pomocą menedżera wyliczania, który konglomeruje wyliczenia wraz ze standardowym interfejsem.
Edycja: Metoda @Helper ma tego doskonały przykład. Pomyśl o tym, aby inne biblioteki definiowały nowe operatory, a następnie mówiły klasie menedżerów, że „hej, ten enum istnieje - zarejestruj go”. W przeciwnym razie możesz zdefiniować Operatory tylko we własnym kodzie - nie byłoby możliwości rozszerzenia.
Wyliczenia są tylko klasami w przebraniu, więc w większości przypadków wszystko, co możesz zrobić z klasą, możesz zrobić z wyliczeniem.
Nie mogę wymyślić powodu, dla którego wyliczenie nie byłoby w stanie zaimplementować interfejsu, a jednocześnie nie mogę wymyślić żadnego dobrego powodu dla nich.
Powiedziałbym, że kiedy zaczniesz dodawać takie elementy jak interfejsy lub metody do wyliczenia, powinieneś naprawdę rozważyć uczynienie go klasą. Oczywiście jestem pewien, że istnieją uzasadnione przypadki wykonywania nietradycyjnych czynności wyliczeniowych, a ponieważ limit byłby sztuczny, opowiadam się za pozwoleniem ludziom robić to, co chcą.
„... więc w większości przypadków wszystko, co możesz zrobić z klasą, możesz zrobić z wyliczeniem”, ale nie mogę powiedzieć, aby moje wyliczenie odziedziczyło po klasie abstrakcyjnej. Tak, nacisk na „w przeważającej części”.
Adam Parkin,
5
Wynika to z faktu, że wszystkie wyliczenia rozszerzają java.lang.Enum, a klasy Java mogą rozciągać się tylko z jednej klasy.
TofuBeer
6
Na przykład, jeśli masz wyliczenie Logger. Następnie powinieneś mieć w interfejsie metody rejestrujące, takie jak debugowanie, informacje, ostrzeżenie i błąd. Sprawia, że Twój kod jest luźno powiązany.
Najczęstszym zastosowaniem tego byłoby połączenie wartości dwóch wyliczeń w jedną grupę i traktowanie ich w podobny sposób. Na przykład zobacz, jak dołączyć do owoców i warzyw .
Jednym z najlepszych przypadków użycia enum z interfejsem są filtry predykatów. Jest to bardzo elegancki sposób na wyeliminowanie braku typowości kolekcji apache (jeśli nie można użyć innych bibliotek).
W powyższym wpisie wspomniane strategie nie podkreślono wystarczająco dobrze, co zapewnia miła, lekka implementacja wzorca strategii za pomocą wyliczeń:
publicenumStrategy{
A {@Overridevoid execute(){System.out.print("Executing strategy A");}},
B {@Overridevoid execute(){System.out.print("Executing strategy B");}};abstractvoid execute();}
Możesz mieć wszystkie swoje strategie w jednym miejscu, bez potrzeby oddzielnej jednostki kompilacji dla każdej z nich. Otrzymujesz ładną dynamiczną wysyłkę tylko dzięki:
Strategy.valueOf("A").execute();
Sprawia, że java jest czytana prawie jak ładny luźny język!
Wyliczenia są jak klasy Java, mogą mieć konstruktory, metody itp. Jedyne, czego nie można z nimi zrobić, to new EnumName(). Instancje są predefiniowane w deklaracji wyliczeniowej.
Co enum Foo extends SomeOtherClass? Więc nie całkiem to samo, co zwykła klasa, w rzeczywistości całkiem inna.
Adam Parkin,
@Adam: Powiedziałbym, że sposoby, w jakie Enums przypominają klasy, są znacznie liczniejsze niż różnice między nimi. Ale nie, nie są identyczni.
scottb
jeśli zdekompilujesz wyliczenie, zobaczysz, że jest to klasa, która rozszerza Wyliczanie i ma już „stałe” utworzone w polach konstruktora / inicjalizacji.
Cosmin Cosmin
3
Kolejna możliwość:
publicenumConditionsToBeSatisfiedimplementsPredicate<Number>{
IS_NOT_NULL(Objects::nonNull,"Item is null"),
IS_NOT_AN_INTEGER(item -> item instanceofInteger,"Item is not an integer"),
IS_POSITIVE(item -> item instanceofInteger&&(Integer) item >0,"Item is negative");privatefinalPredicate<Number> predicate;privatefinalString notSatisfiedLogMessage;ConditionsToBeSatisfied(finalPredicate<Number> predicate,finalString notSatisfiedLogMessage){this.predicate = predicate;this.notSatisfiedLogMessage = notSatisfiedLogMessage;}@Overridepublicboolean test(finalNumber item){finalboolean isNotValid = predicate.negate().test(item);if(isNotValid){
log.warn("Invalid {}. Cause: {}", item, notSatisfiedLogMessage);}return predicate.test(item);}}
i używając:
Predicate<Number> p = IS_NOT_NULL.and(IS_NOT_AN_INTEGER).and(IS_POSITIVE);
Podczas tworzenia stałych w pliku jar często pomocne jest rozszerzenie wartości wyliczania przez użytkowników. Użyliśmy wyliczeń dla kluczy PropertyFile i utknęliśmy, ponieważ nikt nie mógł dodać żadnych nowych! Poniżej działałoby znacznie lepiej.
Zapełniłem JavaFX ComboBox wartościami Enum. Mam interfejs Identyfikowalny (określający jedną metodę: identyfikacja), który pozwala mi określić, w jaki sposób dowolny obiekt identyfikuje się z moją aplikacją do celów wyszukiwania. Ten interfejs umożliwia mi skanowanie list dowolnego rodzaju obiektów (dowolnego pola, którego obiekt może użyć do tożsamości) w celu dopasowania tożsamości.
Chciałbym znaleźć dopasowanie wartości tożsamości na mojej liście ComboBox. Aby skorzystać z tej możliwości w ComboBoxie zawierającym wartości Enum, muszę być w stanie zaimplementować interfejs Identyfikowalny w moim Enum (który, jak się zdarza, jest trywialny w przypadku Enum).
Użyłem wewnętrznego wyliczenia w interfejsie opisującym strategię, aby zachować kontrolę nad instancjami (każda strategia to Singleton).
publicinterfaceVectorizeStrategy{/**
* Keep instance control from here.
*
* Concrete classes constructors should be package private.
*/enumConcreteStrategyimplementsVectorizeStrategy{
DEFAULT (newVectorizeImpl());privatefinalVectorizeStrategy INSTANCE;ConcreteStrategy(VectorizeStrategy concreteStrategy){
INSTANCE = concreteStrategy;}@OverridepublicVectorImageGridIntersections processImage(MarvinImage img){return INSTANCE.processImage(img);}}/**
* Should perform edge Detection in order to have lines, that can be vectorized.
*
* @param img An Image suitable for edge detection.
*
* @return the VectorImageGridIntersections representing img's vectors
* intersections with the grids.
*/VectorImageGridIntersections processImage(MarvinImage img);}
Fakt, że enum implementuje strategię, jest wygodny, aby pozwolić klasie enum działać jako proxy dla jej zamkniętej instancji. który także implementuje interfejs.
jest to rodzaj strategiiEnumProxy: P kod clent wygląda następująco:
Odpowiedzi:
Wyliczenia nie muszą tylko reprezentować zestawów pasywnych (np. Kolorów). Mogą one stanowić więcej obiektów złożonych z funkcjonalnością, a więc jesteś następnie prawdopodobnie chcesz dodać dodatkowej funkcjonalności do nich - na przykład może mieć interfejsy, takie jak
Printable
,Reportable
itd. I komponenty, które obsługują te.źródło
Oto jeden przykład (podobny / lepszy można znaleźć w Effective Java 2nd Edition):
Teraz, aby uzyskać listę operatorów Simple + Complex:
Więc tutaj używasz interfejsu do symulacji rozszerzalnych wyliczeń (co nie byłoby możliwe bez użycia interfejsu).
źródło
Comparable
Przykład podany przez kilka osób tu jest nie tak, skoroEnum
już narzędzia, które. Nie możesz tego nawet przesłonić.Lepszym przykładem jest interfejs definiujący, powiedzmy, typ danych. Możesz mieć wyliczenie do implementacji prostych typów i mieć normalne klasy do implementowania skomplikowanych typów:
źródło
Jest taki przypadek, z którego często korzystam. Mam
IdUtil
klasę ze statycznymi metodami do pracy z obiektami implementującymi bardzo prostyIdentifiable
interfejs:Jeśli utworzę
Identifiable
enum
:Potem mogę to załatwić w
id
ten sposób:źródło
Ponieważ Enums mogą implementować interfejsy, można ich używać do ścisłego egzekwowania wzorca singletonu. Próba stworzenia standardowej klasy singletonu pozwala ...
Wyliczenia jako singletony pomagają zapobiegać tym problemom bezpieczeństwa. To mógł być jeden z głównych powodów, dla których Enums działał jak klasy i implementował interfejsy. Tylko zgadnij.
Więcej informacji na stronie /programming/427902/java-enum-singleton i Singleton w java .
źródło
for inheriting from your singleton and overriding your singleton's methods with something else
. możesz po prostu użyć a,final class
aby temu zapobiecJest to wymagane do rozszerzenia - jeśli ktoś używa API, które opracowałeś, wyliczenia, które definiujesz, są statyczne; nie można ich dodawać ani modyfikować. Jeśli jednak zezwolisz mu na implementację interfejsu, osoba korzystająca z interfejsu API może opracować własne wyliczenie za pomocą tego samego interfejsu. Następnie możesz zarejestrować to wyliczenie za pomocą menedżera wyliczania, który konglomeruje wyliczenia wraz ze standardowym interfejsem.
Edycja: Metoda @Helper ma tego doskonały przykład. Pomyśl o tym, aby inne biblioteki definiowały nowe operatory, a następnie mówiły klasie menedżerów, że „hej, ten enum istnieje - zarejestruj go”. W przeciwnym razie możesz zdefiniować Operatory tylko we własnym kodzie - nie byłoby możliwości rozszerzenia.
źródło
Wyliczenia są tylko klasami w przebraniu, więc w większości przypadków wszystko, co możesz zrobić z klasą, możesz zrobić z wyliczeniem.
Nie mogę wymyślić powodu, dla którego wyliczenie nie byłoby w stanie zaimplementować interfejsu, a jednocześnie nie mogę wymyślić żadnego dobrego powodu dla nich.
Powiedziałbym, że kiedy zaczniesz dodawać takie elementy jak interfejsy lub metody do wyliczenia, powinieneś naprawdę rozważyć uczynienie go klasą. Oczywiście jestem pewien, że istnieją uzasadnione przypadki wykonywania nietradycyjnych czynności wyliczeniowych, a ponieważ limit byłby sztuczny, opowiadam się za pozwoleniem ludziom robić to, co chcą.
źródło
Na przykład, jeśli masz wyliczenie Logger. Następnie powinieneś mieć w interfejsie metody rejestrujące, takie jak debugowanie, informacje, ostrzeżenie i błąd. Sprawia, że Twój kod jest luźno powiązany.
źródło
Najczęstszym zastosowaniem tego byłoby połączenie wartości dwóch wyliczeń w jedną grupę i traktowanie ich w podobny sposób. Na przykład zobacz, jak dołączyć do owoców i warzyw .
źródło
Jednym z najlepszych przypadków użycia enum z interfejsem są filtry predykatów. Jest to bardzo elegancki sposób na wyeliminowanie braku typowości kolekcji apache (jeśli nie można użyć innych bibliotek).
źródło
W powyższym wpisie wspomniane strategie nie podkreślono wystarczająco dobrze, co zapewnia miła, lekka implementacja wzorca strategii za pomocą wyliczeń:
Możesz mieć wszystkie swoje strategie w jednym miejscu, bez potrzeby oddzielnej jednostki kompilacji dla każdej z nich. Otrzymujesz ładną dynamiczną wysyłkę tylko dzięki:
Sprawia, że java jest czytana prawie jak ładny luźny język!
źródło
Wyliczenia są jak klasy Java, mogą mieć konstruktory, metody itp. Jedyne, czego nie można z nimi zrobić, to
new EnumName()
. Instancje są predefiniowane w deklaracji wyliczeniowej.źródło
enum Foo extends SomeOtherClass
? Więc nie całkiem to samo, co zwykła klasa, w rzeczywistości całkiem inna.Kolejna możliwość:
i używając:
źródło
Podczas tworzenia stałych w pliku jar często pomocne jest rozszerzenie wartości wyliczania przez użytkowników. Użyliśmy wyliczeń dla kluczy PropertyFile i utknęliśmy, ponieważ nikt nie mógł dodać żadnych nowych! Poniżej działałoby znacznie lepiej.
Dany:
i:
w słoiku można mieć jedno wyliczenie:
a użytkownik może go rozszerzyć, aby dodać własne kolory:
źródło
Oto mój powód, dla którego ...
Zapełniłem JavaFX ComboBox wartościami Enum. Mam interfejs Identyfikowalny (określający jedną metodę: identyfikacja), który pozwala mi określić, w jaki sposób dowolny obiekt identyfikuje się z moją aplikacją do celów wyszukiwania. Ten interfejs umożliwia mi skanowanie list dowolnego rodzaju obiektów (dowolnego pola, którego obiekt może użyć do tożsamości) w celu dopasowania tożsamości.
Chciałbym znaleźć dopasowanie wartości tożsamości na mojej liście ComboBox. Aby skorzystać z tej możliwości w ComboBoxie zawierającym wartości Enum, muszę być w stanie zaimplementować interfejs Identyfikowalny w moim Enum (który, jak się zdarza, jest trywialny w przypadku Enum).
źródło
Użyłem wewnętrznego wyliczenia w interfejsie opisującym strategię, aby zachować kontrolę nad instancjami (każda strategia to Singleton).
Fakt, że enum implementuje strategię, jest wygodny, aby pozwolić klasie enum działać jako proxy dla jej zamkniętej instancji. który także implementuje interfejs.
jest to rodzaj strategiiEnumProxy: P kod clent wygląda następująco:
Jeśli nie zaimplementował interfejsu, byłby to:
źródło