I've got the class object for an enum (I have a Class<? extends Enum>) and I need to get a list of the enumerated values represented by this enum. The values static function has what I need, but I'm not sure how to get access to it from the class object.
Class.getEnumConstants
If you know the name of the value you need:
Class<? extends Enum> klass = ...
Enum<?> x = Enum.valueOf(klass, "NAME");
If you don't, you can get an array of them by (as Tom got to first):
klass.getEnumConstants();
I am suprised to see that EnumSet#allOf() is not mentioned:
public static <E extends Enum<E>> EnumSet<E> allOf(Class<E> elementType)
Creates an enum set containing all of the elements in the specified element type.
Consider the following enum:
enum MyEnum {
TEST1, TEST2
}
Simply call the method like this:
Set<MyEnum> allElementsInMyEnum = EnumSet.allOf(MyEnum.class);
Of course, this returns a Set, not a List, but it should be enough in many (most?) use cases.
Or, if you have an unknown enum:
Class<? extends Enum> enumClass = MyEnum.class;
Set<? extends Enum> allElementsInMyEnum = EnumSet.allOf(enumClass);
The advantage of this method, compared to Class#getEnumConstants(), is that it is typed so that it is not possible to pass anything other than an enum to it. For example, the below code is valid and returns null:
String.class.getEnumConstants();
While this won't compile:
EnumSet.allOf(String.class); // won't compile
using reflection is simple as calling Class#getEnumConstants():
List<Enum<?>> enum2list(Class<? extends Enum<?>> cls) {
return Arrays.asList(cls.getEnumConstants());
}
Related
Imagine that we have this class.
public class Actor {...}
And then we have a method that needs a parameter that is a type of:
Class<? extends Class<? extends Actor>[]>
Is this even possible? I could not decipher it.
Yes. Let's work from the inside out:
? extends Actor means something that is Actor or any subtypes of Actor.
Class<? extends Actor>[] means an array of Class<T> objects where each object represents a class that is either Actor or is a subtype of Actor.
Class<? extends Class<? extends Actor>[]> represents the class of an array of class objects, where each object is either Actor or one of its subtypes.*
Here's an example that should make it a bit more clear:
//actorClass is a Class<T> object that represents Actor.class
//or any of its subtypes
Class<? extends Actor> actorClass = Actor.class;
//classArray is an array of Class<? extends Actor> objects, and so its type is
//Class<? extends Actor>[]
//You will get a warning about an unsafe cast here because you
//cannot really create an array of generic type, which means the
//RHS type is just `Class[]`.
Class<? extends Actor>[] classArray = new Class[] {
actorClass, actorClass, actorClass
};
//Now we get the class of the array itself, which matches the convoluted
//expression you saw.
Class<? extends Class<? extends Actor>[]> classArrayClass = classArray.getClass();
The important thing to note here is that this giant expression does not represent a class that itself extends an array of Class<? extends Actor> objects. Instead, it represents the class of an array of Class<? extends Actor> objects.
* Technically, you can't create an array of a generic type, which means that Class<? extends Actor>[] really is just Class[]. So eventually you just end up with Class<Class[]>, which is the class that represents an array of Class objects (i.e., just Class[].class).
Interesting. Let's give this type a shorter name "CCA"
CCA = Class<? extends Class<? extends Actor>[]>
expanding the first wildcard,
CCA = all Class<T> where T <: Class<? extends Actor>[]
for array subtyping, we must have
T = A[] where A <: Class<? extends Actor>
Therefore
CCA = all Class<A[]> where A <: Class<? extends Actor>
If we explore the fact that Class is final, then A must be
A = Class<C> or Class<? extends C> where C <: Actor
Therefore
CCA = all Class<Class<C>[]> and Class<Class<? extends C>[]> where C<:Actor
Meaning, CCA covers class objects representing arrays like Class<Actor>[], Class<BadActor>[],
Class<? extends BadActor>[] etc.
On the other hand ... we know that T cannot be arbitrary type in Class<T>. Though syntactically Class<List<String>> is valid, there is really no class for List<String>; there is only class List; therefore only Class<List> makes sense.
And... for arrays, even though there are compile-time types like List<String>[], List<Integer>[], there is only one runtime class, corresponding to List[].
Therefore, CCA is really just Class<Class[]>; there is exactly one object for this type - Class[].class, i.e. the class representing the array type Class[].
Given an object of type CCA, there is nothing interesting you can do with it. I'm curious to know where did you see this type, and what's the actual use case.
I have an enum that stores some metadata for a database table:
static enum DataTable implements TableMetaData {
HISTORIES ("h", Hx.class, HxColumn.HPI_ID),
:
:
private final String e_alias;
private final Class<? extends Row> e_tbl;
private final ColumnMetaData e_idCol;
DataTable(String al,
Class <? extends Row> c1,
ColumnMetaData id)
{...}
#Override public Class<? extends Row> modelClass() { return this.e_tbl; }
:
:
}
The field of interest is e_tbl which stores the model object class corresponding to the database table. All the model object classes in this project implement a Row interface. I'd like to be able to access this field in order to generate instances of this class.
My problem is that I'm using an unchecked cast that I don't know is safe and I haven't been able to figure out how to perform a runtime check to be sure that the model object matches. Here's the code in which the cast occurs:
static final <E extends Row> List<E> doQuery (
final List<JdbcValue> pars,
final String sql,
final TableMetaData dm
)
{
List<E> result = new ArrayList<E>();
#SuppressWarnings("unchecked")
Class<E> cls = (Class<E>) dm.modelClass();
:
:
}
I believe that this is a dangerous cast. The query is intended to generate E instances and those instances will be made using the model class that is contained in the supplied enum constant. The problem is I can't know that E matches the stored class token in the enum. This is a situation in which Class.asSubclass() does not seem to be able to help me.
The problem is that I have a field that is <? extends Row> and I need to make it compatible with <E extends Row>.
One solution would be to refactor the method to that it requires a Class<E> cls parameter rather than the enum. This would provide at least some compile-time assurance that the class token was appropriate for the type of the result list being generated. However this still does not enable me to use the data in the enum; I'd still have to cast it before the method call.
Is there a check I can use?
==================================================
UPDATED 12/6/14
It seems to me that this is a problem without a good, clean solution.
Enums do not support generic type parameters (they can't).
Having incompatible type information at compile-time will happen every time you try to store parameterized types in an enum constant.
Using a parameterized type-safe singleton pattern, as suggested, would enable the compiler to check type safety but the API I have is permeated by these enum classes and I don't feel that I can refactor them into regular classes.
To limit the damage, I wonder if the following reasoning is accurate:
Data associated with enum constants is static and final; here it is also all immutable.
I fully control the data that goes into the enum constants, so I know at run-time that the e_tbl field will always be a Class object of some type that extends Row.
These assumptions admit two approaches that I think have the same flaws. In the enum class, the accessor method is rewritten to:
#Override public <E extends Row> Class<E> modelclass() {
#SuppressWarning("unchecked")
Class<E> cls = (Class<E>) this.e_tbl;
return this.e_tbl; }
I can store the data to the enum to a field that uses a raw type. The raw type interoperates with the generic accessor method and so it compiles but a warning is generated.
I can store the data to the enum to a field that uses a <? extends Row> wildcard type. This won't compile with the generic accessor method (<E> extends Row>) so I have to use an unchecked cast. A warning is still generated.
Since I know that the enum data always extends Row, I think this is probably ok. What I can't do is guarantee that the enum data being retrieved is appropriate for the List type being generated. But I don't think there is any way to control for this aside from documenting that the API user must send the correct TableMetaData constant for the query being returned or the results will be "undefined."
Since enums won't work with generic types, I don't think there is a better solution.
One thing you could do:
Turn TableMetaData into TableMetaData<E> and define the class in terms of E
Get rid of the enum (because they don't support type parameters) and write one class
per enum entry
So the interface looks roughly like
class Histories implements TableMetaData<SpecialRowType> {
Class<SpecialRowType> modelClass();
}
Which should finally allow you to cast use it.
static final <E extends Row> List<E> doQuery (
final List<JdbcValue> pars,
final String sql,
final TableMetaData<E> dm
)
{
List<E> result = new ArrayList<E>();
// type safe, because E refers to the same thing.
Class<E> cls = dm.modelClass();
:
}
Now the compiler can be sure that the ? extends Row class is the same as the E extends Row class, which do have a common ancestor but that doesn't mean that you can cast them to each other.
I have an interface and an enum as follows:
public interface SomeInterface {
......
}
public enum SomeEnum implements SomeInterface {
......
}
public class SomeClass {
public void someMethod(Set<SomeInterface> s) {
...
}
}
Now to call someMethod(Set<SomeInterface> s) I create an enum set containing all of the elements, so I do following:
Set<? extends SomeInterface> choosen = EnumSet.allOf(SomeEnum.class);
SomeClass obj = new SomeClass();
obj.someMethod(choosen)
I get compile time error:
error: method someMethod in class SomeClass cannot be applied to given types;
required: Set<SomeInterface>
found: Set<CAP#1>
reason: actual argument Set<CAP#1> cannot be converted to Set<SomeInterface> by method invocation conversion
where CAP#1 is a fresh type-variable:
CAP#1 extends SomeInterface from capture of ? extends SomeInterface
IMP: I know that the error can be resolved by changing the method to someMethod(Set<? extends SomeInterface> s), but I CAN NOT change the signature of someMethod
Cast your Set to a Set<?> and then to the Set<Whatever> you want. This should resolve your issue...
Casting and ignoring the warning are obviously not type safe. (It may be safe in this particular case, but I would not recommend it anyhow).
But the most appropriate solution also depends on what someMethod is going to do with the Set<SomeInterface>. If it is only going to read from the given set, then you can pass in an unmodifiable view on the set:
Set<? extends SomeInterface> set = ...
Set<SomeInterface> viewOnSet = Collections.unmodifiableSet(set);
someMethod(viewOnSet);
This works because the unmodifiableSet view allows the returned view to be more specific: It is not possible to add new elements to this set, and thus, it is type-safe.
However, if the someMethod is going to modify the set, then you can use the approach that was already mentioned, namely creating a copy of the set with the desired type:
Set<? extends SomeInterface> set = ...
Set<SomeInterface> newSet = new LinkedHashSet<SomeInterface>(set);
someMethod(newSet);
Got another way of achieving what I want is:
Set<SomeInterface> choosen = new HashSet<SomeInterface>(EnumSet.allOf(SomeEnum.class));
someMethod(choosen);
Similar to what McDowell metioned in copyUp() method.
Motivation: I would like to construct an enum that represents all possible values for some family of values (I hesitate to say "class" here). The enum will have additional methods, fields, and perhaps even implement other interfaces. I would then like to pass this enum to another method, where it will iterate over all of the possible values (using Enum.values() and do some work.
I've researched and found that enum Foo actually becomes Foo extends Enum<Foo>. This is why I cannot extend an enum. I have tried to define my method arguments as:
myMethod(Class<?> bar) {...}
myMethod(Class<? extends Enum> bar) {...}
myMethod(Class<? extends Enum<?>> bar) {...}
but inside the method when I try something basic like:
int i = bar.values().length;
it fails. Is there some other way I can do this (or avoid the need to do this)?
Note: I could pass an actual instance of the enum and use bar.getDeclaringClass() to find the enum class (rather than an instance) but this is pretty ugly.
Try using the following:
<E extends Enum<E>> void myMethod(Class<E> enumType) {
E[] values = enumType.getEnumConstants();
...
}
From the getEnumConstants() documentation:
Returns the elements of this enum class or null if this Class object
does not represent an enum type.
Edit: if you're using different enum types implementing a shared interface, you can modify your method in order to be able to call the interface methods. For example:
interface Fooable {
void foo();
}
...
<E extends Enum<E> & Fooable> void myMethod(Class<E> enumType) {
E[] values = enumType.getEnumConstants();
for (E value : values) {
value.foo();
}
}
In such a function:
<T> void foo(T obj)
The type of obj.getClass() is Class<?> and not Class<? extends T>. Why?
The following code works fine:
String foo = "";
Class<? extends String> fooClass = foo.getClass();
So the signature of T#getClass() seems to return a Class<? extends T>, right?
Why is the signature different if T really is a generic?
To overcome the problem (and to make it more clear what I wander about), I have implemented this function:
#SuppressWarnings("unchecked") static <T> Class<? extends T> classOf(T obj) {
return (Class<? extends T>) obj.getClass();
}
Again the question: Why is the cast needed here and not in the String case? And why is the
SuppressWarnings needed? Isn't it always clear from the code that it will always be able to safely do this cast?
Is there any way I can get a Class<? extends T> from obj? If yes, how? If not, why not?
One way would be to use classOf. That would be safe, right? If that is always safe and gives a safe way to really get a Class<? extends T> (instead of a Class<?>), why is there no such function in Java? Or is there?
How about that case:
<T> void bar(T[] array)
array.getClass().getComponentType() again returns a Class<?> and not a Class<? extends T>. Why?
I have implemented this function:
#SuppressWarnings("unchecked") static <T> Class<? extends T> classOf(T[] array) {
return (Class<? extends T>) array.getClass().getComponentType();
}
Is this again safe to use?
To clarify more what I wonder about. Consider this demo code:
static interface I<T> {
Class<? extends T> myClass();
}
static class A implements I<A> {
public Class<? extends A> myClass() {
return this.getClass();
}
}
static <T> void foo(I<T> obj) {
Class<? extends T> clazz = obj.myClass(); // this works
}
This works fine. But the same does not for Object#getClass().
Why wasn't it possible for example to have a generic interface like ClassInstance<T> with the function getClass() and every Java Object automatically implementing this? This would have exactly those improvements I am talking about over the solution to have it extending from a non-generic base class Object.
Or having Object as a generic class:
static abstract class Object<T> {
abstract Class<? extends T> myClass();
}
static class B extends Object<B> {
public Class<? extends B> myClass() {
return this.getClass();
}
}
static <T> void bar(Object<T> obj) {
Class<? extends T> clazz = obj.myClass(); // this works
}
Now think of myClass() as getClass() and think about that the compiler would automatically add that to every class. It would have resolved a lot of those casting issues.
The main question I am talking about is: Why wasn't it made like this?
Or to put it again in different words: Here, I describe in more detail the solution of such classOf function which overcomes the problem. Why wasn't it made like this, i.e. why is the original function not like this?
(I don't really want to get an answer like: the way Java works right now, i.e. extending from a non-generic Object which defines this function, makes this not possible. I am asking why it wasn't solved somehow differently so that it would have been possible.)
The basic problem is that getClass() doesn't return the class because its defined at the Object level. i.e. it is mearly defined as a class which extends object. They could have defined getClass() like.
Class<this> getClass() { /**/ }
but instead its
Class<?> getClass()
which means generics has no understanding of what getClass returns.
In Java generics are just a source level tool for safer development.
The JVM does not know anything about generics.
The Java compiler throws away this information, and all generic types are indeed just Object references at runtime. To compensate for that the compiler inserts the necessary casts.
This procedure is called Type Erasure (Google!).
List<String> x = new ArrayList<String>();
x.add("hello");
String hello = x.get(0);
becomes the following at runtime
List x = new ArrayList();
x.add("hello");
String hello = (String) x.get(0);
To solve your problem you could try to investigate the individual elements in your array (arr[0].getClass()).
There are a couple of not totally accurate answers here. Generics are indeed implemented using type erasure, however this does not mean that all type information is lost. The compiler will erase the type to the lowest bound it can.
So <T extends String> gets erased to String; this is why getClass on a String returns Class<? extends String>. Your unbounded <T> however gets erased to Object; and so getClass returns Class<? extends Object>, i.e. Class<?>
Generics are complex, and they don't always do what you want, but there are ways to work around many things (by improving your bounds, accessing runtime type information via reflection, and passing class objects around). Type erasure is actually a pretty clever solution, undeserving of much of the bad press it has received.
Because of type erasure, the runtime doesn't keep type information for generic arrays. In effect, the JVM internally treats all generic arrays as if they are an Object[].
If you want to get a runtime type, your best option may simply be to call getClass() on the first item in the array. You'll obviously need to find a way to handle the empty case, and the case where the contained objects are of multiple types, etc.