Перечисления Java великолепны. Как и дженерики. Конечно, мы все знаем ограничения последнего из-за стирания типа. Но есть одна вещь, которую я не понимаю: почему я не могу создать перечисление вот так:
public enum MyEnum<T> {
LITERAL1<String>,
LITERAL2<Integer>,
LITERAL3<Object>;
}
Этот параметр общего типа, <T>
в свою очередь, может быть полезен в различных местах. Представьте параметр общего типа для метода:
public <T> T getValue(MyEnum<T> param);
Или даже в самом классе enum:
public T convert(Object o);
Более конкретный пример № 1
Поскольку приведенный выше пример может показаться слишком абстрактным для некоторых, вот более реальный пример того, почему я хочу это сделать. В этом примере я хочу использовать
- Перечисляет, потому что тогда я могу перечислить конечный набор ключей свойств
- Обобщения, потому что тогда у меня может быть безопасность типов на уровне метода для хранения свойств
public interface MyProperties {
public <T> void put(MyEnum<T> key, T value);
public <T> T get(MyEnum<T> key);
}
Более конкретный пример № 2
У меня есть перечисление типов данных:
public interface DataType<T> {}
public enum SQLDataType<T> implements DataType<T> {
TINYINT<Byte>,
SMALLINT<Short>,
INT<Integer>,
BIGINT<Long>,
CLOB<String>,
VARCHAR<String>,
...
}
Каждый литерал перечисления, очевидно, будет иметь дополнительные свойства, основанные на универсальном типе <T>
, и в то же время быть перечислением (неизменяемое, одноэлементное, перечислимое и т. Д. И т. Д.)
Вопрос:
Никто не думал об этом? Это ограничение, связанное с компилятором? Учитывая тот факт, что ключевое слово « enum » реализовано как синтаксический сахар, представляющий сгенерированный код для JVM, я не понимаю этого ограничения.
Кто может объяснить это мне? Прежде чем ответить, подумайте об этом:
- Я знаю, что общие типы стираются :-)
- Я знаю, что есть обходные пути с использованием объектов класса. Они обходные пути.
- Универсальные типы приводят к генерации типов, сгенерированной компилятором, где это применимо (например, при вызове метода convert ()
- Универсальный тип <T> будет в перечислении. Следовательно, он связан каждым из литералов перечисления. Следовательно, компилятор будет знать, какой тип применять при написании чего-то вроде
String string = LITERAL1.convert(myObject); Integer integer = LITERAL2.convert(myObject);
- То же самое относится к параметру универсального типа в
T getvalue()
методе. Компилятор может применять приведение типов при вызовеString string = someClass.getValue(LITERAL1)
enum
в идиому «типизированное перечисление», который мы использовали до Java 1.5. Внезапно вы можете настроить параметры перечисления. Это, вероятно, то, что я собираюсь сделать сейчас.