我有一个通常类型的类 Builder<T> ,它接受一个构造函数参数 Class<T> 所以我可以保持类型 . 这是一个我在java代码中使用很多的类,所以我不想更改签名 . 当我尝试使用这样的构造函数时:
Builder<T>
Class<T>
Builder<List<Number>>(List<Number>::class)
我收到一个错误:“只允许类在类文字的左侧”
有什么办法解决这个问题?我无法更改 Builder 的构造函数,太多的java类依赖它 .
Builder
我理解整个类型的擦除问题,我真的只是想让编译器开心 .
由于generic type erasure List 类对其所有通用实例都有一个实现 . 您只能获得与 List<*> 类型对应的类,因此仅创建 Builder<List<*>> .
List
List<*>
Builder<List<*>>
该构建器实例适用于构建某个列表 . 再次由于类型擦除,您可以在未经检查的强制转换的帮助下自行决定:
Builder(List::class.java) as Builder<List<Number>> Builder(List::class.java as Class<List<Number>>)
另一种方法是创建内联reified帮助函数:
inline fun <reified T : Any> Builder() = Builder(T::class.java)
并按以下方式使用它:
Builder<List<Number>>()
解决方案是使用reified generics与super class tokens结合使用 .
有关解释的方法,请参阅this question . Kotlin中的构造函数不支持reified泛型,但是你可以使用 TypeReference 来编写一个 builder 工厂函数,该函数将在运行时保留实际的泛型参数:
TypeReference
builder
inline <reified T: Any> fun builder(): Builder<T> { val type = object : TypeReference<T>() {}.type return Builder(type) }
然后在 Builder 内部,您可以检查 type 是否为 ParameterizedType ,如果是, type.actualTypeArguments 将包含实际的通用参数 .
type
ParameterizedType
type.actualTypeArguments
例如, builder<List<Number>>() 将在运行时保留有关 Number 的信息 .
builder<List<Number>>()
Number
此方法的局限性在于您不能将非实现的泛型用作具体类型参数,因为必须在编译时知道该类型 .
2 回答
由于generic type erasure
List
类对其所有通用实例都有一个实现 . 您只能获得与List<*>
类型对应的类,因此仅创建Builder<List<*>>
.该构建器实例适用于构建某个列表 . 再次由于类型擦除,您可以在未经检查的强制转换的帮助下自行决定:
另一种方法是创建内联reified帮助函数:
并按以下方式使用它:
解决方案是使用reified generics与super class tokens结合使用 .
有关解释的方法,请参阅this question . Kotlin中的构造函数不支持reified泛型,但是你可以使用
TypeReference
来编写一个builder
工厂函数,该函数将在运行时保留实际的泛型参数:然后在
Builder
内部,您可以检查type
是否为ParameterizedType
,如果是,type.actualTypeArguments
将包含实际的通用参数 .例如,
builder<List<Number>>()
将在运行时保留有关Number
的信息 .此方法的局限性在于您不能将非实现的泛型用作具体类型参数,因为必须在编译时知道该类型 .