Kotlin编程实战:创建优雅、富于表现力和高性能的JVM与Android应用程序
上QQ阅读APP看书,第一时间看更新

6.5 泛型:参数类型的变化和约束

渴望重用代码不应该以牺牲类型安全为代价。泛型可以很好地平衡这个问题。使用泛型,你可以创建可用于不同类型的代码。同时,编译器将验证泛型类或函数是否与非预期类型一起使用。在Java中泛型具有相当好的类型安全性。所以,你可能会想,Kotlin能提供什么改进?事实证明,有很多。

默认情况下,在Java中,泛型强制实行类型不变性——也就是说,如果泛型函数期望一个参数类型T,则不允许替换基类型T或派生类型T,类型必须完全是预期的类型。这是件好事,我们将在本节中进一步讨论。但是如果没有例外,规则又有什么用呢?——而正是在例外的领域,Kotlin脱颖而出。

我们首先来看类型不变性,以及Kotlin如何像Java一样很好地支持它。然后,我们将深入研究更改默认行为的方法。

有时候,你希望编译器允许协变——也就是说,告诉编译器允许使用参数类型T的派生类——除了允许类型T之外。在Java中你使用语法<? extends T>来传递协变,但是有一个问题。当使用泛型类时可以使用该语法,称为“使用点型变(use-site variance)”,但在定义类时不能使用该语法,称为“声明点型变(declaration-site variance)”。在Kotlin中,这两个都可以使用,我们很快就会看到。

其他时候,你希望告诉编译器允许逆变——也就是说,在期望类型T的地方允许参数类型T的超类。再一次,Java允许带有语法<? super T>的逆变,但只能在“使用点”,而不是“声明点”使用。Kotlin允许逆变既可以在“声明点”使用,也可以在“使用点”使用。

在本节中,我们将首先回顾Java中可用的类型变化。在这里复习一下将有助于为接下来更深入的讨论设置好背景。然后,你将学习“声明点”和“使用点”的协变语法。在那之后,我们将深入研究逆变,最后,总结如何为变化混合多个约束。