泛型在Kotlin中允许创建通用和类型安全的数据结构和函数。主要特点:Kotlin在编译时实现了泛型类型系统,与Java相似,但具有更严格的类型检查和扩展的变异性语法(协变性和逆变性)。
泛型的限制:
T() 是禁止的)。变异性:
协变性的例子:
interface Producer<out T> { fun produce(): T }
逆变性的例子:
interface Consumer<in T> { fun consume(item: T) }
与Java的区别:
out 替代 ? extends,in 替代 ? super)。?,只有 in/out)。问题: "在Kotlin中能否将数组数组(Array<Array<Int>>)声明为Array<out Array<Int>>,并且在尝试向该数组写入时会发生什么?"
答案: 是的,可以声明为 Array<out Array<Int>>,但这样的数组变为只读(read-only):
val arr: Array<out Array<Int>> = Array(1) { Array(1) { 0 } } arr[0] = arrayOf(1, 2, 3) // 编译错误!
尝试写入值将导致错误——因为带有 out 参数的泛型数组不允许写入元素,因为这将破坏类型安全。
故事
团队尝试创建一个带有 out 参数类型的泛型对象数组,然后通过 set(index, value) 向其中放入值。代码编译通过,但在运行时引发错误,导致多个函数不可用。
故事
一次在将库从Java迁移到Kotlin时,保留了通配符类型(? extends ...),而在Kotlin中只是复制了类型而没有修改为out/in。结果是——编译未通过,而在 "遍历" 时错误在运行时爆发,增加了调试的复杂性。
故事
使用in/out变异性与用户定义的类,但将修饰符搞混了,声明了接口Stack<in T>而不是Stack<out T>。这导致无法从栈中返回元素:方法的签名违反了系统的out/in契约。