When I run (ParameterizedType)getClass().getGenericSuperclass(),
expect to be T, but it's PropertyEditorSupport, and can't be casted to
ParameterizedType;
If you want to have access to the T
aka the type-parameter, the appropriate reflection method is Class.getTypeParameters
.
// Test.java:
class Generic<T> {
}
class Main {
public static void main(String[] args) {
final Generic<Integer> gint1 = new Generic<Integer>();
System.err.println("gint1's type-parameter: "
+ gint1.getClass().getTypeParameters()[0]);
}
}
If you run the code above you get the following:
$ javac Test.java
$ java Main
gint1's type-parameter: T
Notice that the type parameter is not resolved as Integer but as T
since this information in not available at run-time.
If access to this information is important for you, then you have two straight forward options.
A. the object contains a reference to the actual type class:
class Generic<T> {
public final Class<T> type;
public Generic(Class<T> type) {
this.type = type;
}
public Class<T> type() {
return type;
}
}
class Main {
public static void main(String[] args) {
final Generic<Integer> gint2 = new Generic<>(Integer.class);
System.err.println("gint2's type-parameter: " + gint2.type().getSimpleName());
}
}
// Output will be "gint2's type-parameter: Integer".
B. You create a subclass that gives a concrete class for that type-parameter:
import java.lang.reflect.*;
class Generic<T> {
}
class IntegerGeneric extends Generic<Integer> {
}
class Main {
public static void main(String[] args) {
final Generic<Integer> gint3 = new IntegerGeneric();
final Generic<Double> gint4 = new Generic<Double>() {};
System.err.println("gint3's type-parameter: "
+ ((ParameterizedType)gint3.getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
System.err.println("gint4's type-parameter: "
+ ((ParameterizedType)gint4.getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
}
}
// Output:
// gint3's type-parameter: class java.lang.Integer
// gint4's type-parameter: class java.lang.Double
Notice that gint4 class is not Generic<Double>
but at anonymous inner class that extends it due to the {}
following the constructor... this is an alternative to a full class DoubleGeneric ...
declaration.
Of these two alternatives, A. and B., A. is preferable as in general one should avoid to rely on reflection; amongst other things it is more prone to hide run-time errors and the code is more difficult to maintain.
I want to know what's the different when use
(ParameterizedType)getClass().getGenericSuperclass() with a class has
a none generic type super class.
If you look-up the Type
documentation, the class of the reference returned by this methods, it indicates that it is an "umbrella" super-interface for all object/data types available in the Java language including even primitives ... so for a class that does not have a generic superclass I guess it would return a subclass of type that reflect that...
A quick experiment reveals that in fact it would return a 'Class' object so it would be equivalent to to getSuperclass().
Perhaps others can give a more informed perspective on this, but I think this might have been a bit of a misnaming ... I think getSuperType() or something like that would have been more appropriate. Perhaps initially it only supported generics in an older Java version (1.5?) and eventually was extended to cover other data types but this is a wild guess of mine without looking into its history.