Kotlin中可空类型
常见的几种空判断
?.
安全的调用,当一个值存在时,才会执行它的下一步操作
?:
Elvis操作符,或者合并运算符
!!.
非空断言,用来保证某个变量不为空,除此之外还有 !is as? 等
原理:Kotlin 在方法参数上标注@Nullable,在实现上,采用if..else来对可空情况进行判断,对比Java8的Optional,兼容性、性能更好,开销更低,语法还简洁。
Either
Either只有两个子类型:Lift、Rigit,如果Either[A, B] 对象包含的是 A 的实例,那么它就是 Left 实例,否则就是 Right 实例。
sealed class Either<A, B> {
class Left<A, B>(val value: A) : Either<A, B>()
class Right<A, B>(val value: B) : Either<A, B>()
}
let
public inline fun <T, R> T.let(block: (T) -> R): R = block(this)
调用某对象的let函数,该对象会作为函数的参数,在函数块内可以通过it指代该对象。返回值为函数块的最后一行或这顶return表达式
类型检查
is 关键字
类型智能转换
对于Java中,判断类型 instanceof 后还需要手动强制转换类型,Kotlin中使用 is 判断后自动转换,当然也可以使用 as 关键字转换。配合泛型封装下:
fun <T> cast(original: Any): T? = original as? T
Any
Java中Object作为Java类的顶层类型,Kotlin中使用Any作为非空类型的超类。Kotlin不分原始类型。
Any是所有非空类型的跟类型,Any?则是所有类型的跟类型。
Nothing是没有实例的类型,Nothing类型的表达式不会产生任何值,任何返回Nothing的表达式之后的语句都是无法执行的。Kotlin中return、throw等返回值都是Nothing
Kotlin 中 Int 类型等同于 int , Int? 等同于 Integer
泛型
优势:
类型检查,能在编译时就帮助检查作物;
更加语义化;
自动类型转换,获取数据时不需要进行类型强制转换;
更加通用化代码
fun main(args: Array<String>) {
//无法像java一样声明一个list
// val arrayList = ArrayList()//err
//水果盘子只能盛Fruit类型的
val applePlate = FruitPlate(Apple(1.0))
// val nodlesPlate = FruitPlate(Noodles(1.0))//err
//只能T : Fruit, T : Ground两种限定
cut(Watermelon(3.0))
// cut(Apple(3.0))//err
}
class Plate<T>(val t: T)//盘子
open class Fruit(val weight: Double)//水果
class Apple(weight: Double) : Fruit(weight)//苹果
class Banana(weight: Double) : Fruit(weight)//香蕉
class FruitPlate<T : Fruit>(val t: T)//水果盘子
class Noodles(weight: Double)//面条
interface Ground//刀
class Watermelon(weight: Double) : Fruit(weight), Ground
fun <T> cut(t: T) where T : Fruit, T : Ground {
print("You can cut me.")
}
泛型擦除
获取所有类型信息的泛型类
open class GenericsToken<T> {
var type: Type = Any::class.java
init {
val superClass = this.javaClass.genericSuperclass
type = (superClass as ParameterizedType).actualTypeArguments[0]
}
}
val gt = object : GenericsToken<Map<String, String>>() {}
匿名内部类在初始化的时候就会绑定父类或父接口的相应信息,这样就能通过获取父类或父接口的泛型类型信息来实现特定需求。可以利用这样的一个类来获取泛型的类型。
也可以使用内联函数获取泛型,只需要加上 reified 关键字
inline fun <reified T> getType() = T::class.java
协变
在定义的泛型类和泛型方法的泛型参数前面加上 out 关键字,表明这个泛型类及泛型方法是协变
类型 A 是类型 B 的子类型,那么Generic<A> 也是 Generic<B> 的子类型,比如 String 是 Any 的子类型,那么 List<String>也是 List<Any> 的子类型。
//List接口
public interface List<out E> : Collection<E>
//Kotlin中可以实现
val stringList: List<String> = ArrayList()
val anyList: List<Any> = stringList
//而在Java中编译不通过
List<String> stringList = new ArrayList<>();
List<Object> objectLis = stringList;//err
Kotlin中 list 中没有 add 等方法,一旦创建就不能在修改,这就是泛型协变要付出的代价
与Java比较:只能作为消费者,只能读取不能添加
Kotlin:<out T>
Java:<? extends T>
逆变
和 out 相反, in 关键字代表逆变。A 是类型 B 的子类型,那么 Generic<B> 反过来是 Generic<A> 的子类型
val numberComparator = Comparator<Number> { n1, n2 ->
n1.toDouble().compareTo(n2.toDouble())
}
val doubleList = mutableListOf(2.0, 3.0)
doubleList.sortWith(numberComparator)
expect fun <T> MutableList<T>.sortWith(comparator: Comparator<in T>): Unit
与Java比较:只能作为生产者,只能添加,读取受限
Kotlin:<in T>
Java:<? super T>