Java enums are great. So are generics. Of course we all know the limitations of the latter because of type erasure. But there is one thing I don't understand, Why can't I create an enum like this:
public enum MyEnum<T> {
LITERAL1<String>,
LITERAL2<Integer>,
LITERAL3<Object>;
}
This generic type parameter <T>
in turn could then be useful in various places. Imagine a generic type parameter to a method:
public <T> T getValue(MyEnum<T> param);
Or even in the enum class itself:
public T convert(Object o);
More concrete example #1
Since the above example might seem too abstract for some, here's a more real-life example of why I want to do this. In this example I want to use
- Enums, because then I can enumerate a finite set of property keys
- Generics, because then I can have method-level type-safety for storing properties
public interface MyProperties {
public <T> void put(MyEnum<T> key, T value);
public <T> T get(MyEnum<T> key);
}
More concrete example #2
I have an enumeration of data types:
public interface DataType<T> {}
public enum SQLDataType<T> implements DataType<T> {
TINYINT<Byte>,
SMALLINT<Short>,
INT<Integer>,
BIGINT<Long>,
CLOB<String>,
VARCHAR<String>,
...
}
Each enum literal would obviously have additional properties based on the generic type <T>
, while at the same time, being an enum (immutable, singleton, enumerable, etc. etc.)
Question:
Did no one think of this? Is this a compiler-related limitation? Considering the fact, that the keyword "enum" is implemented as syntactic sugar, representing generated code to the JVM, I don't understand this limitation.
Who can explain this to me? Before you answer, consider this:
- I know generic types are erased :-)
- I know there are workarounds using Class objects. They're workarounds.
- Generic types result in compiler-generated type casts wherever applicable (e.g. when calling the convert() method
- The generic type <T> would be on the enum. Hence it is bound by each of the enum's literals. Hence the compiler would know, which type to apply when writing something like
String string = LITERAL1.convert(myObject); Integer integer = LITERAL2.convert(myObject);
- The same applies to the generic type parameter in the
T getvalue()
method. The compiler can apply type casting when callingString string = someClass.getValue(LITERAL1)
enum
into a "typesafe enum" idiom we used before Java 1.5. Suddenly, you can have your enum members parameterized. That's probably what I'm going to do now. – Marko Topolnik