我有一个这样的课程
public class RequestDataEditor<T> extends PropertyEditorSupport {
@Override
public void setAsText(String text) {
MyData<T> value;
try {
//(ParameterizedType)getClass().getGenericSuperclass()
value = JacksonUtil.parse(text, new TypeReference<MyData<T>>() {
});
} catch (Exception e) {
value = null;
}
setValue(value);
}
}
当我运行(ParameterizedType)getClass().getGenericSuperclass()
时,
期望是T,但它是PropertyEditorSupport,并且无法转换为ParameterizedType;
如果我删除extends PropertyEditorSupport
,那么我可以获得通用类型。(事实证明这是错误的,我在这里犯了错误。)
似乎我们不能使用(ParameterizedType)getClass().getGenericSuperclass()
从父类没有泛型类的类中获取泛型类型。
那么我怎样才能获得像RequestDataEditor这样的类的泛型类型?
not duplicate with the question,我想知道在使用(ParameterizedType)getClass().getGenericSuperclass()
并且类具有非通用类型超类时的不同之处。
答案 0 :(得分:2)
(ParameterizedType)getClass()。getGenericSuperclass()将获取当前类的超类,而不是通用类。您需要当前类的泛型类型而不是其超类。在您的示例中,这将是不可能的,因为此数据在运行时不再可用。可能的解决方案可能是:
public class RequestDataEditor<T> extends PropertyEditorSupport {
private final Class<T> genericType;
public RequestDataEditor(Class<T> genericType) {
this.genericType = genericType;
}
@Override
public void setAsText(String text, ) {
MyData<T> value;
try {
//use genericType here
value = JacksonUtil.parse(text, new TypeReference<MyData<T>>() {
});
} catch (Exception e) {
value = null;
}
setValue(value);
}
}
我知道这并不是你想要达到的目标,但它是你能得到的最接近的(据我所知)。
答案 1 :(得分:2)
当我运行(ParameterizedType)getClass()。getGenericSuperclass()时, 期望是T,但它是PropertyEditorSupport,并且不能被转换为 ParameterizedType;
如果您想要访问T
又称类型参数,则适当的反映方法是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]);
}
}
如果您运行上面的代码,您将获得以下内容:
$ javac Test.java
$ java Main
gint1's type-parameter: T
请注意,type参数未解析为Integer,而是解析为T
,因为此信息在运行时不可用。
如果您对此信息的访问权限很重要,那么您有两个直接的选择。
一个。该对象包含对实际类型类的引用:
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中。您创建了一个子类,为该类型参数提供了具体的类:
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
请注意,gint4类不是Generic<Double>
,而是由于构造函数后面的{}
而扩展它的匿名内部类...这是完整class DoubleGeneric ...
声明的替代方法。
在这两种替代方案中,A。和B.,A是优选的,因为通常应该避免依赖反射;除此之外,它更容易隐藏运行时错误,代码更难以维护。
我想知道使用时有什么不同 (ParameterizedType)getClass()。getGenericSuperclass()与一个类有 一个非通用类型超类。
如果你查看Type
文档,这个方法返回的引用类,它表明它是Java语言中可用的所有对象/数据类型的“伞形”超级接口,包括甚至原语...所以对于没有通用超类的类,我猜它会返回一个反映那个类型的子类......
快速实验表明,实际上它会返回一个'Class'对象,因此它等同于getSuperclass()。
也许其他人可以对此提供更明智的观点,但我认为这可能有点误解......我认为getSuperType()或类似的东西会更合适。也许最初它只支持较旧的Java版本(1.5?)中的泛型,并最终扩展到涵盖其他数据类型,但这是我的一个疯狂猜测,而不考虑其历史。