• 【Kotlin学习】Kotlin的类型系统——基本数据类型和其他基本类型、集合与数组


    基本数据类型和其他基本类型

    基本数据类型:Int、Boolean及其他

    kotlin并不区分基本数据类型和包装类型,你使用的永远是同一个类型。在运行时,数字类型会尽可能地使用最高效的方式来表示。Int类型会被编译成java基本数据类型int。不可行的例外是泛型类,比如集合。用作泛型类型参数的基本数据类型会被编译成对应的java包装类型。
    整数类型——Byte、Short、Int、Long
    浮点数类型——Float、Double
    字符类型——Char
    布尔类型——Boolean

    可空的基本数据类型:Int?、Boolean?及其他

    kotlin中的可空类型不能用java的基本数据类型表示,因为null只能被存储在java的引用类型的变量中,只要使用了基本类型的可空版本,它就会被编译成对应的包装类型。JVM不支持用基本数据类型作为类型参数,所以泛型类必须始终使用类型的包装表示

    数字转换

    kotlin不会自动地把数字从一种类型转换成另一种

    image.png
    必须进行显式转换

    image.png

    每一种基本数据类型(Boolean除外)都定义有转换函数:toByte()、toShort()等。这些函数支持双向转换。为了避免意外情况,kotlin要求转换必须是显式的,尤其是在比较装箱值的时候。比较两个装箱值的equals方法不仅会检查它们存储的值,还要比较装箱类型。在java中new Integer(42).equals(new Long(42))会返回false

    基本数据类型字面值

    kotlin支持一下这些在代码中书写数字字面值的方式
    1.使用后缀L表示Long类型(长整型)字面值:123L
    2.使用标准浮点数表示Double(双精度浮点数)字面值:0.12、2.0、1.2e10
    3.使用后缀F表示Float类型(浮点数)字面值:123.4f、456F
    4.使用前缀0x或者0X表示十六进制字面值:0x123
    5.使用前缀0b或者0B表示二进制字面值:0b0101

    当你书写数字字面值的时候一般不需要使用转换函数,即使你没有用上面的这些语法,当你使用数字字面值去初始化一个类型已知的变量时,又或是把字面值作为实参传给函数时,必要的转换会自动发生。此外算术运算符也被重载了,它们可以接收所有适当的数字类型

    Any和Any?:根类型

    Any是kotlin所有非空类型的超类型。但在java中,Object只是所有引用类型的超类型,而基本数据类型并不是类层级结构的一部分。和java一样,把基本数据类型的值赋给Any类型的变量时会自动装箱。Any是非空类型,所以Any类型的变量不能持有null值,在kotlin中如果你要持有任何可能值的变量,包括null就要使用Any?类型。在底层Any类型对应Object。所有kotlin类都包含toString equals hashCode,这些方法都继承自Any。但Any不能使用其他Object的方法,比如wait和notify,但可以通过手动把值转换成Object来调用。

    Unit类型:Kotlin的void

    Unit类型完成了java中void一样的功能,而且可以省略。大多是情况下你不会留意到void和Unit之间的区别。若果你的kotlin函数使用Unit作为返回类型并且没有重写泛型函数,在底层它会被编译成旧的void函数。它们的不同之处在于Unit是一个完备的类型,可以作为类型参数,而void不行。只存在一个值是Unit类型,这个值也叫做Unit,并且在函数中会被隐式返回。当你在重写返回泛型参数的函数时非常有用,只需让方法返回Unit类型的值。

    Nothing类型:这个函数永不返回

    许多测试库都有一个叫做fail的函数,它通过抛出带有特定消息的异常来让当前测试失败,一个包含无限循环的函数也永远不会成功结束。

    Nothing类型没有任何值,只有被当作函数返回值使用,或者被当作泛型函数返回值的类型参数使用才会有意义。

    注意!返回Nothing的函数可以放在Elvis运算符的右边来做先决条件检查

    image.png

    集合与数组

    可空性和集合

    对前后一致的类型系统来说有一点十分关键:知道集合是否可以持有null元素,和知道变量值是否可以为null同等重要

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GPuZxiZh-1652951635803)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/df8e8a4090df42e3a8d715a81a595653~tplv-k3u1fbpfcp-zoom-in-crop-mark:1956:0:0:0.image?)]

    List<Int?>是能持有Int?类型值的列表:换句话说,可以持有Int或者null。如果一行文本可以被解析,那么就向result列表中添加一个整数,否则添加null。从kotlin1.1开始可以使用函数String.toIntOrNull来简化例子。

    注意!变量自己类型的可空性和用作类型参数的可空性是有区别的,一个包含可空Int的列表和包含Int的可空列表是有区别的。List<Int?>是列表中的单个值是可空的,列表本身不为null,但列表的每个值可以为null,而List?是整个列表是可空的。我们要小心决定什么是可空的,是集合元素还是集合本身

    遍历一个包含可空值的集合并过滤掉null是一个非常常见的操作,因此kotlin提供了filterNotNull函数来完成它。这种过滤也影响了集合的类型,此时List<Int?>会变成List<Int>,因为过滤保证了集合不会再包含任何为null的元素

    只读集合与可变集合

    与java有别,kotlin把访问集合数据的接口和修改集合数据的接口分开了。这种区别存在于最基础的使用集合的接口之中:Collection。使用这个接口,可以遍历集合中的元素、获取集合大小、判断集合中是否包含某个元素,以及执行其他从该集合中读取数据的操作,但这个接口没有任何添加或移除元素的方法。使用MutableCollection接口可以修改集合中的数据。它继承了Collection接口,还提供了方法来添加和移除元素、清空集合等。

    一般的规则是在代码的任何地方都使用只读接口,只在代码需要修改集合的地方使用可变接口的变体

    使用集合接口时牢记只读集合不一定是不可变的。如果你使用的变量有一个只读接口类型,他可能只是同一个集合的众多引用中的一个,任何其他的引用都可能拥有一个可变接口类型,所以只读集合并不总是线程安全的。

    kotlin集合与java

    每一种java集合接口在kotlin中都有两种表示:一种是只读的,一种是可变的

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OGrHfCc3-1652951635809)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/df16ec85164d47c2b54bdadf742bad5c~tplv-k3u1fbpfcp-zoom-in-crop-mark:1956:0:0:0.image?)]
    可变接口直接对应java.util包中的接口,而它们的只读版本中缺少了所有产生改变的方法

    image.png

    注意!setOf和mapOf返回的是java标准类库中类的实例(1.0中是这样),在底层它们都是可变的,kotlin的未来版本可能会使用真正不可变的实现类作为它们两个的返回值。

    当你需要调用一个java方法并把集合作为实参传给它时,可以把任意只读或可变接口的值作为实参传递。 因为java并不会区分只读与可变集合,即使kotlin声明为只读,java代码也能修改这个集合。所以,如果你写了一个kotlin函数,使用了集合并传递给了java,你有责任使用正确的参数类型,这取决于你调用的java代码是否会去修改集合。同时也要注意包含非空类型元素的集合类,如果你向java方法传递了这样的集合,该方法就可能在其中写入null值,kotlin没有办法在不影响性能的情况下禁止它的发生。

    作为平台类型的集合

    我们提到过kotlin把那些定义在java代码中的类型看成平台类型,kotlin没有任何关于平台类型的可空型信息,所以编译器允许kotlin代码将其视为可空或非空。同样java中声明的集合类型的变量也被视为平台类型。一个平台类型的集合本质上就是可变性未知的集合,kotlin代码将其视为只读或者可变的,实际上你想要执行的所有操作都能正常工作

    当你重写或者实现签名中有集合类型的java方法时这种差异才变得重要,你需要决定使用哪一种kotlin类型来表示这个java类型
    1.集合是否可空
    2.集合中的元素是否可空
    3.你的方法会不会修改集合

    对象和基本数据类型的数组

    kotlin中的一个数组是一个带有类型参数的类,其元素类型被指定为相应的类型参数

    在kotlin中创建数组

    1.arrayOf函数创建一个数组,它包含的元素是指定为该函数的实参

    2.arrayOrNulls函数创建一个给定大小的数组,包含的是null元素,它只能用来创建包含元素类型可空的数组

    3.Array构造方法接受数组的大小和一个lambda表达式,调用表达式来创建每一个数组元素。这就是使用非空元素类型来初始化数组,但不用显式地传递每个元素的方式

    image.png
    lambda接收数组元素的下标并返回放在数组下标位置的值,这里可以省略数组元素的类型

    kotlin代码中最常见的创建数组的情况之一是需要调用参数为数组的java方法时,或是调用带有vararg参数的kotlin函数时。在这些情况下通常已经将数据存储在集合中,只需将其转换成数组即可,可使用toTypedArray方法来执行此操作

    image.png
    和其它类型一样,数组类型的类型参数始终会变成对象类型。如果你需要创建没有装箱的基本数据类型的数组,必须使用一个基本数据类型数组的特殊类

    kotlin提供了若干独立的类,如Int类型值的数组叫做IntArray。还有CharArray等其他类型。所有这些类型都被编译成普通的java基本数据类型数组,比如int[]等。因此这些数组中的值存储时并没有装箱,而是使用了可能的最高效的方式

    要创建一个基本数据类型的数组
    1.该类型的构造方法接收size参数并返回一个使用对应基本数据类型默认值(通常是0)初始化好的数组

    2.工厂函数(IntArray的intArrayOf,以及其他数组类型的函数)接受变长参数的值并创建存储这些值的数组

    3.另一种构造方法,接受一个大小和一个用来初始化每个元素的lambda

    image.png

    假如你有一个持有基本数据类型装箱后的值的数组或者集合,可以用对赢得转换函数把它们转换成基本数据类型的数组,比如toIntArray

    kotlin中也有一套和集合相同的用于数组的扩展函数,lambda编程中的绝大部分函数也适用于数组,包括基本数据类型的数组,注意这些方法的返回值是列表不是数组

    文末

    我总结了一些Android核心知识点,以及一些最新的大厂面试题、知识脑图和视频资料解析。

    需要的小伙伴直接点击文末小卡片免费领取哦,以后的路也希望我们能一起走下去。(谢谢大家一直以来的支持,需要的自己领取)

    Android学习PDF+架构视频+面试文档+源码笔记

    部分资料一览:

    • 330页PDF Android学习核心笔记(内含8大板块)

    • Android学习的系统对应视频

    • Android进阶的系统对应学习资料

    • Android BAT大厂面试题(有解析)

    领取地址:

    在这里插入图片描述

  • 相关阅读:
    quarkus数据库篇之二:无需数据库也能运行增删改查(dev模式)
    Python学生公寓管理系统的设计与实现毕业设计源码181047
    javaScript关于闭包的理解
    【华为OD机试真题 python】贪吃蛇【2022 Q4 | 200分】
    “易+”开源网易易盾 GameSentry 正式开源,做游戏安全保障的尖兵利刃
    ORB-SLAM2 ---- Frame::AssignFeaturesToGrid函数
    【Mysql学习笔记】关键字顺序以及执行顺序
    您可知道如何通过`HTTP2`实现TCP的内网穿透???
    Spark 之 deploy
    Python 安装win32com失败
  • 原文地址:https://blog.csdn.net/star_nwe/article/details/124867399