本文共 3515 字,大约阅读时间需要 11 分钟。
Kotlin的类型系统虽然与Java有截然不同的默认处理方式,但在某些方面也为我们提供了更多的灵活性和安全机制。其中,可空性(Nullable Types)是Kotlin中非常值得关注的一个特性。以下将详细解释可空性在Kotlin中的使用及其相关功能。
在Kotlin中,可空性通过在类型名后面添加问号(?)来表示。例如,String变量可以声明为String?,表明它可以存储null引用。这种设计与传统Java的可空性思想有很大不同,因为Kotlin默认所有类型均为非空类型。
使用可空类型会带来一些限制:
为了处理这些限制,Kotlin提供了多种安全调用运算符:
Kotlin允许使用lateinit修饰符来表示延迟初始化。这种属性可以在不直接初始化的情况下使用。例如:
class MyService { fun performAction(): String = "foo"}class MyTest { private lateinit var myService: MyService fun setUp() { myService = MyService() } fun testAction() { println(myService.performAction()) }} 延迟初始化的属性必须在初始化前正确配置,否则会抛出UninitializedPropertyAccessException。
为了更方便地处理可空类型,Kotlin允许为类和对象定义扩展函数:
isEmpty:判断对象是否为空。例如,String的扩展方法isEmpty可以用来判断字符串是否为空。isBlank:判断字符串是否为空或仅由空白字符组成。isNullOrEmpty:类似于isEmpty和isBlank,但通常用于集合或序列为空检查。isNullOrBlank:结合了isNull和isBlank的检查功能。Kotlin的泛型类型参数默认是可空的,这有时可能导致意外的null值传递。要排除这种情况,可以指定上界。例如:
fun printHashcode(t: T) { println(t.hashCode())}// 正确使用方式:printHashcode(null) // 这里会抛出编译错误,因为T不能存储null 如果要明确T不能为null,可以指定上界:
funprintHashcode(t: T) { println(t.hashCode())}printHashcode(null) // 还是会抛出编译错误
要排除null值,可以指定上界为Nonnull:
funprintHashcode(t: T) { println(t.hashCode())}printHashcode(null) // 这里会直接报错,因为T不能存储null
Kotlin可以识别和处理多种可空性注解风格,例如:
@Nullable@NotNull@NotNullIf ...如果Java代码中没有可空性注解,Kotlin会将其视为Platform类型(平台类型),这将导致在Kotlin代码中可能需要进行额外的处理。例如:
// Java代码中:public String getName() { return name; } 如果name在Java中可以为null,那么在Kotlin中使用时,需要正确进行null处理:
fun yellAt(person3: Person3) { println(person3.name.toUpperCase())} 如果在Kotlin中name为null,这会抛出NullPointerException,除非进行了正确的null检查。
Kotlin的基本数据类型与Java的基本数据类型相似,但有一些差异:
null赋值给val name: String。List泛型中,如果没有指定上界,会将其视为List<Nothing>。?符号。例如,String?会被编译为java.lang.String。Kotlin简化了数值转换,用户可以直接使用原始类型进行操作,而无需显式进行装箱和拆箱。例如:
val b: Byte = 1val l = b + 1Lfoo(l)
这样会直接将Byte和Long进行加法运算。
Any类型是Kotlin中的根类型,表示所有非空类型的超类型。Any?表示可空的根类型。当使用Any类型时,可以接受任何非空类型的值。当使用Any?类型时,可以接受null和任何非空类型的值。
在Kotlin中,Unit类似于Java中的void类型,用于表示没有有意义返回值的函数。Unit类型可以作为函数的返回类型,或作为类型参数。例如:
fun f(): Unit {} Unit类型只有一个值——Unit本身,可以隐式地返回。
Nothing类型表示函数永远不会有返回值。它可以用来表示极端的情况,比如:
fun fail(message: String): Nothing { throw IllegalArgumentException(message) }fun arrayRun(): Nothing { while (true) {} }Kotlin中的集合在类型系统中也非常灵活:
列表类型:
List: 表示列表中的元素都不为空。List<Int>: 表示列表中的每个元素可以为空。List<Int>?: 表示列表本身可以为空,且每个元素可以为空。集合接口:
Collection 是只读的集合接口。MutableCollection 是可变的集合接口,提供了修改操作的方法。数组:
arrayOf、arrayOfNulls或Array构造函数来创建数组。Kotlin的集合接口将访问集和修改集分开:
Collection: 只读接口,适用于简单遍历和大小查询。MutableCollection: 继承自Collection,提供了修改操作的方法。像添加、移除、清空元素等功能。需要注意的是,只读集合并不一定是不可变的。即使一个集合是只读的,如果它被多个代码路径引用,其中一个代码路径修改它,其他代码路径可能会感知到修改。
这篇文章通过逐步解释Kotlin中的可空性、基础数据类型、集合等内容,帮助开发者更好地理解Kotlin的类型系统,从而更高效地开发Kotlin应用。
转载地址:http://fhpxz.baihongyu.com/