Wyliczenia Java są świetne. Więc są generyczne. Oczywiście wszyscy znamy ograniczenia tego ostatniego z powodu wymazywania typów. Ale jest jedna rzecz, której nie rozumiem, dlaczego nie mogę utworzyć takiego wyliczenia:
public enum MyEnum<T> {
LITERAL1<String>,
LITERAL2<Integer>,
LITERAL3<Object>;
}
Ten parametr typu ogólnego <T>
może z kolei być przydatny w różnych miejscach. Wyobraź sobie ogólny parametr typu dla metody:
public <T> T getValue(MyEnum<T> param);
Lub nawet w samej klasie enum:
public T convert(Object o);
Bardziej konkretny przykład nr 1
Ponieważ powyższy przykład może wydawać się zbyt abstrakcyjny dla niektórych, oto bardziej prawdziwy przykład, dlaczego chcę to zrobić. W tym przykładzie chcę użyć
- Wyliczenia, ponieważ wtedy mogę wyliczyć skończony zestaw kluczy właściwości
- Generics, ponieważ wtedy mogę mieć bezpieczeństwo typu na poziomie metody do przechowywania właściwości
public interface MyProperties {
public <T> void put(MyEnum<T> key, T value);
public <T> T get(MyEnum<T> key);
}
Bardziej konkretny przykład nr 2
Mam wyliczenie typów danych:
public interface DataType<T> {}
public enum SQLDataType<T> implements DataType<T> {
TINYINT<Byte>,
SMALLINT<Short>,
INT<Integer>,
BIGINT<Long>,
CLOB<String>,
VARCHAR<String>,
...
}
Każdy literał wyliczenia miałby oczywiście dodatkowe właściwości oparte na typie ogólnym <T>
, będąc jednocześnie wyliczeniem (niezmiennym, pojedynczym, wyliczalnym itp.)
Pytanie:
Czy nikt o tym nie pomyślał? Czy to jest ograniczenie związane z kompilatorem? Biorąc pod uwagę fakt, że słowo kluczowe „ enum ” jest zaimplementowane jako cukier składniowy, reprezentujący wygenerowany kod w JVM, nie rozumiem tego ograniczenia.
Kto może mi to wyjaśnić? Zanim odpowiesz, zastanów się:
- Wiem, że typy ogólne są usuwane :-)
- Wiem, że istnieją obejścia przy użyciu obiektów Class. To obejścia.
- Typy ogólne skutkują rzutami typów generowanych przez kompilator wszędzie tam, gdzie ma to zastosowanie (np. Podczas wywoływania metody convert ()
- Typ ogólny <T> znajdowałby się w wyliczeniu. Stąd jest on związany przez każdy z literałów wyliczenia. Dlatego kompilator wiedziałby, jaki typ zastosować podczas pisania czegoś takiego
String string = LITERAL1.convert(myObject); Integer integer = LITERAL2.convert(myObject);
- To samo dotyczy parametru typu ogólnego w
T getvalue()
metodzie. Kompilator może zastosować rzutowanie typu podczas wywoływaniaString string = someClass.getValue(LITERAL1)
enum
zamień idiom „wyliczenie bezpieczne dla typów”, którego używaliśmy przed Javą 1.5. Nagle możesz sparametryzować członków wyliczenia. To prawdopodobnie to, co teraz zrobię.