Kotlin 为什么泛型类型属性可以为null?

Kotlin 为什么泛型类型属性可以为null?,kotlin,Kotlin,我正在尝试使用泛型类型的lateinit不可空属性创建一个参数化类: class Test<T> { private lateinit var t : T private lateinit var s : String } 类测试{ 私有lateinit变量t:t 私有lateinit变量s:String } 后者是允许的,但前者是不允许的。编译器返回以下错误: 错误:(7,11)“lateinit”修饰符不允许用于可为空的属性 由于我没有声明t?,我不明白为什

我正在尝试使用泛型类型的
lateinit
不可空属性创建一个参数化类:

class Test<T> {

   private lateinit var t : T

   private lateinit var s : String

}
类测试{
私有lateinit变量t:t
私有lateinit变量s:String
}
后者是允许的,但前者是不允许的。编译器返回以下错误:

错误:(7,11)“lateinit”修饰符不允许用于可为空的属性

由于我没有声明
t?
,我不明白为什么会这样

默认上限(如果未指定)为
Any?
()

换句话说,当您使用
T
时,Kotlin假设这可能是任何类型,无论是原语、对象还是可为空的引用

要解决此问题,请添加一个上限类型:

class Test<T: Any> { ... }
类测试{…}
对类型参数的可空性有以下说明

类型参数的可空性:

默认情况下,的所有类型参数 Kotlin中的函数和类可以为null。任何类型,包括 可为空的类型,可以替换为类型参数;在这种情况下,, 允许使用类型参数作为类型的声明 null,即使类型参数T没有以问题结尾 马克

如何使类型参数不为null

要使类型参数为非null,需要指定一个非null 它的上限。这将拒绝将可为null的值作为参数

请注意,类型参数是 如果要将类型标记为可空,则需要在末尾加上问号,并且 没有问号的类型是非空的。下一节显示 可空性的另一个特例:来自Java的类型 代码


T、 当用作类型参数时,始终为null。(所有类型参数都可以为空)。您不需要声明
t?
,只需要声明
t
。要使用声明上限,请执行此操作
公共类Foo
任何
都不可为空)

可为空的类型参数
Any?
是Kotlin中所有类型的超类型。因此,当您没有为类型参数
t
指定任何上限时,默认边界是
any?

例如:

类测试{}

类测试{}

这导致在以下示例中,
T
可为空:

class Test<T> {
    private var t : T          // T can have a nullable type
}
class Test<T : Any> {
    private var t: T           // T is non-null
    private var t2: T?         // T can be used as nullable
}
具有
T:Any
的泛型类型只能使用非空类型参数进行实例化,并防止使用可空类型参数进行实例化:

val test: Test<Int> = Test()   // OK
val test: Test<Int?> = Test()  // OK
val test: Test<Int> = Test()   // OK
val test: Test<Int?> = Test()  // Error
值得注意的是,如果根据业务逻辑有一种更具体的类型,那么您可以使用一种更具体的类型。例如,如果希望上界为
T:Any
,则可以使用
T:SomeProduct
。它只需要是非空的

这将确保类的用户不能使用可为null的类型参数进行实例化,并且您对
lateinit var
始终为非null的假设将成立



就这样!希望能有所帮助。

顺便说一句,语法
T?
是不允许的,所以技术上没有不一致。
T?
允许在
T
中使用,而不是声明
T
。所以
valx:T?
是有效的。您可以阅读关于T的更多信息吗?在这里
class Test<T : Any> {
    private lateinit var t: T
}