【问题标题】:Is it impossible to instantiate a parameterized type through reflection?通过反射来实例化参数化类型是不可能的吗?
【发布时间】:2021-03-11 08:57:25
【问题描述】:

假设您正在编写一个库,它将作用于传递给它的客户端类(即无法更改客户端代码)。

class ClientClass {
    public GenericClientClass<AnotherClientClass>  someField;
}

我想做的是通过反射实例化 someField 。比如:

class LibraryClass{
    public instantiateAllFields(Object obj){
        //iterate through all fields of obj.class, and instantiate them
    }
}

客户端字段的唯一要求是存在不带参数的构造函数。 (例如 GenericClientClass() {} )

这样做的目的是创建一个高度自动化的测试库,目前用于我自己的目的。

我已经能够为几乎所有情况(数组、对象、基元、泛型数组等)实现上述内容;然而,这个特殊的案例让我很难过。

field.getType().newInstance() 不起作用,因为删除了泛型类型参数。

field.getGenericType() 不起作用,因为它返回的是类型,而不是类。

如果这是一个已知的泛型类,我可以创建一个特殊情况来处理它。例如:

            Class<?> genClass = ((Class<?>)((ParameterizedType)field.getGenericType()).getActualTypeArguments()[0]);
            JArray jArray = new JArray(true,n,genClass);
            field.set(object, jArray);

...我猜我可以为 ArrayList、HashMap 等东西做到这一点。

但是,我想介绍一般情况,并且能够实例化任何可以传递到库中的泛型类(使用单个参数和零参数构造函数)。

有什么想法吗?

请注意,泛型参数的类型已知。我可以通过 field.getGenericType() 得到它。

【问题讨论】:

标签: java generics reflection


【解决方案1】:

没有“参数化类型的实例”这样的东西;或者,更确切地说,具有不同类型参数的参数化类型的实例之间没有区别。类型参数只是编译器用来强制类型正确性的东西。

如果你在运行时实例化它,编译器不在循环中。所以你只需要创建一个“原始”/“通配符”类型的实例,然后转换它;你必须自己负责确保演员阵容实际上是安全的。

假设GenericClientClass不是抽象的,并且有一个没有参数的构造函数:

someField = (GenericClientClass<AnotherClientClass>) GenericClientClass.class.getConstructor().newInstance();

并适当地处理由此产生的未经检查的强制转换警告。

【讨论】:

  • 谢谢,这非常有帮助。但是,有没有办法通过反射进行投射?我不能使用代码(GenericClientClass&lt;AnotherClientClass&gt;),因为这些类是在客户端中定义的,而不是在库中。
  • 没有。强制转换也(大部分)只是编译时的事情:它只是告诉编译器它需要相信你知道的类型信息比它知道的更多的方式。反射 API 很大程度上不知道泛型。
  • 我明白了 - 有道理。然后我遇到的问题是GenericClientClass.class.getConstructor().newInstance() 实例丢失了有关其参数类型的信息,因此当我尝试递归实例化它自己的字段时,我得到的是普通对象而不是指定的类型。 ...我想我可以通过递归调用显式传递参数的类型,然后使用它来正确实例化更深的字段。应该做的工作。再次感谢:)
猜你喜欢
  • 2021-03-23
  • 2020-07-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多