从类文件中实例化通用参数化类型

时间:2013-04-02 03:41:48

标签: java reflection

所以客户端将以下列方式创建一个类:

public class Tester implements Test<Type1, Type2, Type3> {
    @override
    public method1(...)
    ...
}

然后客户端将.class文件(I.E. Tester.class)传递给我们。

然后,我们希望实例化客户端的类,并根据泛型使用的类型运行其method1。到目前为止,我有以下代码,但我不认为我走的是正确的道路:

    //tempClass = <ClassName>.class
    Type[] genericTypes;
    Type[] genericInterfaces = tempClass.getGenericInterfaces();
    if(genericInterfaces[0] instanceof ParameterizedType){
        genericTypes = ((ParameterizedType)genericInterfaces[0])
                        .getActualTypeArguments();
    }
    Class<Tester<genericTypes[0], genericTypes[1], genericTypes[2]>> classTest
        = ( Class<Tester<genericTypes[0], genericTypes[1], genericTypes[2]>>) tempClass
    Constuctor<...> = ... //get the constructor
    //Create the new instance by calling .newInstance()

但是eclipse在Class&gt;中给了我很多错误。线,所以我不认为这是正确的道路。我做错了什么?

1 个答案:

答案 0 :(得分:1)

这里有几个问题......

首先,Classname.class本身就是静态构造 - 它甚至被称为 class literal 。因此,无法在运行时提供类型名称,这就是Eclipse抱怨您尝试这样做的原因。要获取给定类名作为字符串的Class对象,可以使用 Class.forName

Class<?> tempClass = Class.forName("Tester");

(完全限定名称且没有.class后缀)。

第二,Tester<Type1, Type2, Type3>也是如此。必须在编译时知道类型参数。现在,我不确定为什么你需要在这个地方进行演员表,但我看到了几个可能的原因:

  • 为了确保tempClass所代表的类确实实现了适当的接口 - 那么即使它是一个语法上合法的构造也是没用的。转换不能动态检查泛型类型参数,因为它们也完全是编译时构造 - 由于type erasure,它们在运行时不可用。要检查给定的Class对象A是否是Class对象B所代表的类型的子类/实现,我们可以使用Class.isAssignableFrom

    if (B.isAssignableFrom(A)) {
        // ...
    }
    
  • 为避免警告 - 抱歉,此类强制转换真的未选中,因为无法确保其在运行时的正确性 - 再次,由于类型erasuer。在您知道强制转换的地方使用@SuppressWarnings,并且Java类型系统太愚蠢,无法验证您的声明。

无论如何,不​​要去上课。相反,转换newInstance调用的结果。现在,至于运行正确的方法......现在您拥有所需的所有信息,分为两部分:对象调用方法,并键入已实现接口的参数。