🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
### Any? 可空类型(Nullable Types) [TOC] 可空类型是Kotlin类型系统的一个特性,主要是为了解决Java中的令人头疼的 NullPointerException问题。 我们知道,在Java中如果一个变量可以是 null ,来那么使用它调用一个方法就是不安全的,因为它会导致: NullPointerException(NPE) 。 **Kotlin把可空性(nullability)作为类型系统的一部分,Kotlin编译器可以直接在编译过程中发现许多可能的错误,并减少在运行时抛出异常的可能性。** Kotlin的类型系统和Java相比,**首要的区别就是Kotlin对可空类型的显式支持**。 #### **null 是什么** 在Java中, null 是任何引用类型的默认值,不严格的说是所有Object类型的默认值。 **这里的 null 既不是对象也不是一种类型,它仅是一种特殊的值,我们可以将其赋予任何引用类型,也可以将 null 转化成任何类型**。在编译和运行时期,将 null 强制转换成任何引用类型都是可行的,在运行时期都不会抛出空指针异常。 >[info]【注意】,这里指的是任何Java的引用类型。在遇到基本类型 int long float double short byte 等的时候,情况就不一样了。而且还是个坑。编译器不会报错,但是运行时会抛NPE。空指针异常。这是Java中的自动拆箱导致的。 代码示例 ``` Integer nullInt = null; // this is ok int anotherInt = nullInt; // 编译器允许这么赋值, 但是在运行时抛 NullPointerException ``` >[info]要时刻注意这一点:Integer的默认值是null而不是0。当把null值传递给一个int型变量的时候,Java的自动装箱将会返回空指针异常。 #### **Kotlin中的 null** 在Kotlin中,针对Java中的 null 的杂乱局面,进行了整顿,作了清晰的界定,并在编译器级别强制规范了可空null变量类型的使用。 ~~~ fun main(args: Array<String>) { //null 跟 null 是相等的 println(null == null)//true println(null != null)//false //null 这个值比较特殊, null 不是 Any 类型 println("null is Any ="+null is Any)//false //null 是 Any? 类型 println("null is Any? ="+null is Any?)//true //null 的类型是 Nothing? var a= null //a=1 // 报错Error:(14, 7) Kotlin: The integer literal does not conform to the expected type Nothing? //对 null 进行加法运算 //对应的重载运算符的函数定义在 kotlin/Library.kt 里面 println("1"+null)//1null println(null+20)//null20 //但反过来就不可以,因为Int没有重载传入 null 参数的 plus() 函数。 //println(1+null) // 报错error: none of the following functions can be called with the arguments supplied: } ~~~ 查看源码如下图Int的plus方法 ![](https://box.kancloud.cn/9944accd8a4ee94f9423d67d4cd3831f_370x571.png) #### **可空类型 String? 与安全调用 ?.** 代码如下 ![](https://box.kancloud.cn/be79536d14ef53e23f78a1a5ad228dc1_595x197.png) 如上图,编译器就直接编译失败:`Null can not be a value of a non-null type String`,这样**通过编译时强制排除空指针的错误,大大减少了出现NPE的可能。然而在Java中这样编译时是不报错可以通过,运行时才能检测出错误**。如下代码 ![](https://box.kancloud.cn/418de54945c89bc88df4e472569046d1_605x248.png) ![](https://box.kancloud.cn/3c9d4380d0a4fa8aac8cac41c11d9b21_693x125.png) 另外,如果我们确实需要传入一个可空的参数,我们可以使用可空类型 String? 来声明一个可以指向空指针的变量。 可空类型可以用来标记任何一个变量,来表明这个变量是可空的(Nullable)。例如: Char? ,Int? , MineType? (自定义的类型)等等。 ![](https://box.kancloud.cn/0d14754d448de69502e82b57ff9f4f5c_458x185.png) 可以看出:普通 String 类型,是不允许指向 null 的;而可空 String? 类可以指向 null 。 使用一个可空变量来调用函数: ![](https://box.kancloud.cn/3b723787b53350f8085f8d8fcb3abb2c_477x203.png) 变量 str: String? 是可空的类型,调用只能通过安全调用 ?. 或者非空断言调用 !!. 。具体详情可查看本系列之空安全之安全调用和非空断言专节,另外,如果异常需要捕获到进行特殊处理的场景,在Kotlin中仍然使用 try ... catch 捕获并处理异常。 #### **可空类型的层次体系** 就像 Any 是在非空类型层次结构的根, Any? 是可空类型层次的根。 由于 Any? 是Any的超集,所以, Any? 是Kotlin的类型层次结构的最顶端。 ![](https://box.kancloud.cn/c6dc72dd970e1b14cb9a17a744516182_152x137.png) 代码示例 ~~~ fun main(args: Array<String>) { println(1 is Any)//true println(1 is Any?)//true println(null is Any)//false println(null is Any?)//true println(Any() is Any?)//true } ~~~