我有一个通用类型的类Builder<T>
,它接受一个构造函数参数Class<T>
,所以我可以保持类型。这是一个我在java代码中使用很多的类,所以我不想改变签名。
当我尝试使用这样的构造函数时:
Builder<List<Number>>(List<Number>::class)
我收到错误:&#34;只允许在类文字的左侧使用类&#34;
有什么方法可以解决这个问题?
我无法更改Builder
的构造函数,太多的java类依赖它。
我理解整个类型的擦除问题,我真的只是想让编译器开心。
答案 0 :(得分:15)
由于generic type erasure List
类对其所有通用实例都有一个实现。您只能获得与List<*>
类型相对应的类,因此只能创建Builder<List<*>>
。
该构建器实例适合构建某些内容的列表。再次由于类型擦除,你可以在未经检查的演员的帮助下自己决定:
Builder(List::class.java) as Builder<List<Number>>
Builder(List::class.java as Class<List<Number>>)
另一种方法是创建内联的具体辅助函数:
inline fun <reified T : Any> Builder() = Builder(T::class.java)
并按以下方式使用:
Builder<List<Number>>()
答案 1 :(得分:7)
解决方案是将reified generics与super class tokens结合使用。
有关解释的方法,请参阅this question。 Kotlin中的构造函数不支持reified泛型,但是你可以使用那里描述的TypeReference
编写一个builder
工厂函数,它将在运行时保留实际的泛型参数:
inline <reified T: Any> fun builder(): Builder<T> {
val type = object : TypeReference<T>() {}.type
return Builder(type)
}
然后在Builder
内,您可以检查type
是否为ParameterizedType
,如果是,type.actualTypeArguments
将包含实际的通用参数。
例如,builder<List<Number>>()
将在运行时保留有关Number
的信息。
此方法的局限性在于您不能将非实体泛型用作具体类型参数,因为必须在编译时知道该类型。
答案 2 :(得分:0)
如果您已在项目中使用gson库(例如json解析)。为此提供了一个类。 com.google.gson.reflect.TypeToken()
。所以你可以使用类似的东西,
Builder<List<Number>>(object : TypeToken<List<Number>>() {}.type::class)
答案 3 :(得分:-3)
您可能只想使用以下样式,
Array<Number>::class.java
如果您想要类似Class<T>