我尝试过这个,但是代码没有编译。
class GenericClass<T>() {
private var arr : Array<T>? = null
{
arr = Array<T>(10, { null })
}
}
我尝试过这个,但是代码没有编译。
class GenericClass<T>() {
private var arr : Array<T>? = null
{
arr = Array<T>(10, { null })
}
}
这段代码报告了两个编译器错误:一个是关于可为空类型,另一个是关于泛型。
可为空类型。Kotlin强制使用可为空引用类型的规则,在T可能被实例化为String的情况下,让arr成为Array类型,这样编译器不允许您将null放入此数组中。如果您需要null值,则必须将类型更改为Array:
class GenericClass<T>() {
private var arr : Array<T?>? = null
{
arr = Array(10, { null }) // No need to specify type arguments again
}
}
泛型。上述示例仍存在编译时错误,因为我们正在尝试构造一个未知类型 T 的数组。请注意,这个问题在Java中也存在。 Kotlin编译成JVM字节码涉及两件事:
这意味着在字节码中,Kotlin必须创建某些具体类型的数组,而不是未知类型T的数组。每当它看到Array时,它可以创建对象数组,但是在这种情况下,这不起作用,例如:
fun test() {
fun foo(srts: Array<String?>) {
// ...
}
val gc = GenericClass<String>()
foo(gc.arr)
}
在这里,我们试图传递 Object[],但需要的是 String[],所以会出现运行时错误。
这就是为什么 Kotlin 拒绝创建 T 类型的数组。您可以通过明确抑制类型系统来解决此问题,即使用类型转换:
class GenericClass<T>() {
val arr : Array<T?>
{
arr = Array<Any?>(10, { null }) as Array<T?>
}
}
在这里,我们明确请求创建一个任意类型的数组(编译为Object[]),然后将其强制转换为T类型的数组。编译器会发出警告,但会遵守我们的意愿。
请注意,上述有问题的示例仍然存在,即如果您将以这种方式创建的数组传递到期望字符串数组的位置,则运行时会失败。
arrayOfNulls
。 - bashorarrayOfNulls
是具体化的,因此无法转换为泛型。 - Poweranimal方法
val array : Array<T?> = kotlin.arrayOfNulls<T>(size)
从文档中
/**
*Returns an array of objects of the given type with the given [size],
*initialized with null values.
*/
public fun <reified @PureReifiable T> arrayOfNulls(size: Int): Array<T?>
arrayOfNulls
是具体化的,因此无法转换为泛型。 - Poweranimalreified T
进行参数化。这个解决方案受到了答案 https://dev59.com/wVgQ5IYBdhLWcg3w-oxw#41946516 的启发。class GenericClass<T> protected constructor(
private val arr : Array<T?>
) {
companion object {
inline fun <reified T>create(size: Int) = GenericClass<T>(arrayOfNulls(size))
}
}
fun main() {
val strs = GenericClass.create<String>(10)
...
}
import GenericClass.Companion.fill
class GenericClass<T> {
private var arr : Array<T?>? = null
fun show() {
print(arr?.contentToString())
}
private fun fill(arrayFactory: (size: Int) -> Array<T?>) {
this.arr = arrayFactory(10)
}
@PublishedApi
internal fun `access$fill`(arrayFactory: (size: Int) -> Array<T?>) = fill(arrayFactory)
companion object {
inline fun <reified T>GenericClass<T>.fill() {
`access$fill`(arrayFactory = { size -> arrayOfNulls(size) })
}
}
}
fun main() {
val strs = GenericClass<String>()
strs.fill()
strs.show()
}
@Suppress("UNCHECKED_CAST")
fun <T> genericArrayOfNulls(size: Int): Array<T?> {
return arrayOfNulls<Any?>(size) as Array<T?>
}