2017-03-02 121 views
2

我有这样一类获取泛型类

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

泛型是编译时安全检查。它们在运行时不包含任何可用的类型信息。 – 4castle

+0

@ 4castle但是,如果'RequestDataEditor'类没有父类,那么我们可以得到泛型类型 – JackYe

+0

如果删除'extends PropertyEditorSupport','getGenericSuperclass()'只返回'class Object'。请提供[mcve]进行测试。 – kennytm

回答

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 

注意,类型参数未解析为整数,但作为T因为这种信息无法在运行时。

如果访问这些信息对您很重要,那么您有两个简单的选项。

A.对象包含实际类型的类的引用:

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语言中甚至包括primitives ...所以对于没有泛型超类的类我想它会返回一个反映该类型的子类...

一个快速实验显示,实际上它会返回一个'Class'对象它相当于getSuperclass()。

也许其他人可以对此有更多的了解,但我认为这可能有点误会......我认为getSuperType()或类似的东西会更合适。也许最初它只支持较旧的Java版本(1.5版本)中的泛型,并最终扩展到涵盖其他数据类型,但这是我的一个猜测,而没有考虑它的历史。

+0

感谢您的详细解释! – JackYe

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); 
    } 
} 

我知道这是不是正是你试图达到的目标,但它是你可以得到的最接近(据我所知)。 。

+0

Thx。我犯了一个错误。你的回答帮助我更深入地理解getGenericSuperclass()方法。 – JackYe

+0

不客气。你解决了你的问题吗? – mahieus