以下源代码
fun main(args: Array<String>) {
println("Hello, world!")
val mutableIntList = mutableListOf(1, 2, 3)
addInt(4, mutableIntList) // No compile-time error
addAnotherInt(5, mutableIntList) // Compile-time error
println(mutableIntList)
}
fun <T: Number> addInt(item:T,
list:MutableList<in T>){
list.add(item)
}
fun <T: Number> addAnotherInt(item:T,
list:MutableList<in Number>){
list.add(item)
}
函数addInt
和addAnotherInt
将MutableList
的逆变Number
作为参数。但是在main
函数中,一行正常编译而另一行不正常编译。
我还检查了这些函数生成的java代码,它们看起来完全相同。
函数addInt
和addAnotherInt
之间可能有什么区别?
答案 0 :(得分:8)
in Number
表示&#34; Number
或其超类型&#34;。 Int
不是&#34; Number
或其超类型&#34;,它是它的子类型。
简单来说,您声明您的addAnotherInt()
想要的列表至少与接受任何类型的Number
一样通用。
相比之下,addInt
声明item: T
和list: MutableList<in T>
。 T
本身被声明为函数的自由类型变量,这意味着它将绑定在每个特定的调用站点。所以当你说
addInt(4, mutableIntList)
Kotlin根据第一个参数将T
绑定到Int
并将其传播到第二个参数,现在是MutableList<in Int>
。你传入的MutableList<Int>
与那种类型兼容,所以Kotlin很满意。
如果您宣布
val mutableIntList: MutableList<Number> = mutableListOf(1, 2, 3)
然后代码将被编译,因为现在列表是一般的,并且你可以添加任何Number
。
答案 1 :(得分:2)
您的代码将使用数字列表进行编译:
val mutableIntList = mutableListOf<Number>(1, 2, 3)
但由于该类型推断为MutableList<Int>
,因此您无法将其用作MutableList<in Number>
。这转换为 Java 等效MutableList<? super Number>
,意味着您可以向列表添加任何Number
。但是无法向Long
添加MutableList<Int>
。
您的第二种方法addInt()
稍微严格一些,并在您的用例中翻译MutableList<? super Int>
。因此你可以这样使用它。两种方法都能够使用MutableList<Number>
。