文章目录
- [1.null 引用](#1.null 引用)
- 2.可空类型
-
- [2.1.安全的调用 ?.](#2.1.安全的调用 ?.)
- [2.2.Elvis 操作符 ?:](#2.2.Elvis 操作符 ?:)
- [2.3.非空断言 !!.](#2.3.非空断言 !!.)
- 2.4.类型检查
- 2.5.类型智能转换
- [3.比 Java 更面向对象的设计](#3.比 Java 更面向对象的设计)
-
- 3.1.Any:非空类型的根类型
- [3.2.Any?: 所有类型的根类型](#3.2.Any?: 所有类型的根类型)
- 3.3.自动装箱和拆箱
- 3.4.数组类型
- 4.泛型:让类型更加安全
1.null 引用
null,不多解释,都知道代表了什么,比如:该值没有初始化、不合法、不需要、不存在。
其次,就是我们熟知 NullPointerException 问题,它往往让我们编写的 Java 程序变得脆弱。虽然 Java 中也针对它做了很多事情,例如 自定义异常、注解@NotNull、Optional等。
2.可空类型
Kotlin 提供了一种崭新的思路来解决由 null 引发的问题,这就是在类型层面提供一种"可空类型"。这在处理 NEP 问题上非常容易。
在 Kotlin 中,我们可以在任何类型后面加上"?",比如"Int?",实际上等同于"Int?=Int or null"。先看一个示例:
kotlin
// 允许s为null
val s: String? = null
// 没有报错,而是打印了 null
println(s?.length)
如上,这里的 ?. 称为安全调用,当 s 存在时,才会调用 length 方法。
2.1.安全的调用 ?.
如上示例
2.2.Elvis 操作符 ?:
类似于 Java 的三目运算,但 Kotlin 是类型安全的,如下:
kotlin
// 允许s为null
val s: String? = null
val result = s?.length ?: "没有值"
// 打印结果:没有值
println(result)
2.3.非空断言 !!.
kotlin
// 允许s为null
val s: String? = null
// 报错:NullPointerException
println(s!!.length)
如上,如果 s.length 为 null 时就会报错 NEP。
2.4.类型检查
要判断一个对象是什么类型。在 Java 中,一般使用 A instanceof T 来判断 A 是 T 或者 T 的子类的一个实例。而在 Kotlin 中,我们可以用"is"来判断。如下:
kotlin
// 允许s为null
val s: String = "ddd"
// 打印结果分别是 true 和 false
println(s is String)
println(s !is String?)
2.5.类型智能转换
Kotlin 中可以将一个变量的类型转变为另一个种类,隐式完成的,如下:
kotlin
var s: Any = "Hello"
// true
println(s is String)
s = 6
// false
println(s is String)
3.比 Java 更面向对象的设计
在 Kotlin 的类型系统中,并不区分原始类型(基本数据类型)和包装类型,我们使用的始终是同一个类型。虽然从严格意义上,我们不能说 Kotlin 是一门纯面向对象的语言,但它显然比 Java 有更纯的设计。
让我们一起来看看Kotlin的类型结构,如下:
需要注意的是,以上的类型结构中省略了除 String、Int 之外的一些原生类型,比如Double、Long等。
3.1.Any:非空类型的根类型
与 Object 作为 Java 类层级结构的顶层类似,Any 类型是 Kotlin 中所有非空类型(如String、Int)的超类,如上图所示。
与 Java 不同的是,Kotlin 不区分"原始类型"(primitive type)和其他的类型,它们都是同一类型层级结构的一部分。如果定义了一个没有指定父类型的类型,则该类型将是 Any 的直接子类型。
如果你为定义的新类型指定了父类型,则该父类型将是新类型的直接父类型,但是新类型的最终根类型为 Any。
如果你的类型实现了多个接口,那么它将具有多个直接的父类型,而 Any 同样是最终的根类型。
另外,Kotlin 把 Java 方法参数和返回类型中用到的 Object 类型看作 Any(更确切地说是当作"平台类型")。当在 Kotlin 函数中使用 Any 时,它会被编译成 Java 字节码中的 Object。
3.2.Any?: 所有类型的根类型
如果说 Any 是所有非空类型的根类型,那么 Any? 才是所有类型(可空和非空类型)的根类型。这也就是说,?Any? 是 ?Any 的父类型。
3.3.自动装箱和拆箱
我们发现,Kotlin 中并没有 int、float、double、long 这样的原始类型,取而代之的是它们对应的引用类型包装类Int、Float、Double、Long。除了以上代表数值的类型,还有布尔(Boolean)、字符(Char)、字符串(String)及数组(Array)。
3.4.数组类型
Kotlin 中这样创造数组:
kotlin
// 声明长度为0的数字
val funList = arrayOf()
// 声明并初始化长度为t的数组
val funList = arrayOf(n1,n2 ... nt)
Kotlin 中 Array 并不是一种原生的数据结构,而是一种 Array 类,甚至我们可以将 Kotlin 中的 Array 视作集合类的一部分。
由于 Kotlin 的类型智能转换,编译器能够隐式推断出 funList 元素类型。当然,我们也可以手动指定类型:
kotlin
value funList = arrayOf<T>(n1, n2 ... nt)
在 Kotlin 中,还为原始类型额外引人了一些实用的类:IntArray、CharArray、ShortArray 等,分别对应 Java 中的i nt[]、char[]、short[] 等。
但是需要注意,IntArray 不是 Array 的子类,两者创建的相同值的对象,不是相同的对象。
4.泛型:让类型更加安全
Kotlin 的泛型就不多说了,和 Java 的很相似,百度看一下示例即可。