views:

100

answers:

3

Given two classes like this:

class Example1<A,B> {

  public Map<A,B> someMap = new HashMap<A,B>();

}

class Example2 extends Example1<URL, URL> {


}

Is there any way using reflection that I can determine the component types of the Map for Example2?

I know I can do:

ParameterizedType t = (ParameterizedType) Example2.class.getFields()[0].getGenericType();

But from there, I can't seem to figure out that the two components are URLs.

Does anyone have any ideas?

+1  A: 

Because Java generics are implemented via "erasure", this information is not available at runtime through reflection.

EDIT: it seems I missed some detail of the question. In this sort of specialized case the type information is available.

Darron
You'd be correct if the reflection began with calling `getClass` on an instance of `HashMap<URL, URL>` itself. Then Kirk's code would print something like `K` and `V` (the names of the type parameters; pretty useless). But because the reflection here begins with a class that *inherits* `HashMap<URL, URL>`, the types supplied for `K` and `V` are stored in the class metadata for `Example2`, and so Kirk's code has some information to read from.
Daniel Earwicker
Rob is asking about a class, not an object. The information is available at runtime.
Tom Hawtin - tackline
+5  A: 

Darron is not completely correct. The following will print out what you want:

ParameterizedType superClass = (ParameterizedType) Example2.class.getGenericSuperclass();
System.out.println(superClass.getActualTypeArguments()[0]);
System.out.println(superClass.getActualTypeArguments()[1]);

Prints out:

class java.net.URL
class java.net.URL
Kirk Woll
To clarify on the "type erasure" point, all the generic type information is actually encoded in the Java .class file. Where it's **not** encoded is within the runtime execution of a method. That is why the information is accessible through reflection, but is not accessible through standard language constructs (i.e. new T[] or o instanceof T).
Kirk Woll
A: 

Hi Kirk,

Your answer is not quite correct - you are returning the generic types of the Class, not of "someMap" field type.

Of course, in the example given the arguments to someMap were , which are the same as the arguments to the class, but if someMap were defined with , and the map types were not both URL, then there is a question about how to map the generic type's parameters to the field's.

A better example might have been:

class Example1<A,B> {

  public Map<B,A> someMap = new HashMap<B,A>();

}

class Example2 extends Example1<URL, String> {


}

In this case, to answer the question of: what are someMap's types in Example2? The answer should be:

java.lang.String java.net.URL

But, I still can't figure out how to get that.

Rob Moffat