Kotlin 空类型安全与智能类型转换

一、前言

Kotlin 中的类与接口 中我们已经讲了 Kotlin 的 接口扩展方法,今天我们来讲 Kotlin 中的 空类型安全智能类型转换

二、Kotlin 空类型安全

2.1、空类型安全概念

Java 语言中是没有空类型安全这一概念的,所以写 Java 代码经常会出现空指针异常,但是 Kotlin 致力于消除空引用所带来的危险,所以就有了空类型安全概念。

下面这段代码在 Kotlin 中是无法编译通过的,因为 Kotlin 的 String 是不能接受空值的,所以这个赋值操作是不被允许的。

var nonNull: String = "Hello"
nonNull = null  // 不可空类型,不能赋值为 null
// 访问长度的话,不需要空判断
val length = nonNull.length

IDE 报错如下所示:
在这里插入图片描述

但是如果我们非得定义一个空值,也是有办法的,Kotlin 为了 100% 兼容 Java,必须得实现接收空值,所以要接收空值可以在定义的时候加一个 ?。

但是这个时候这个变量就可能是空值,所以访问的时候就会比较严格,比如下面代码中的 nullable.length 就会报错,因为可能触发空指针异常。

var nullable: String? = "Hello"
nullable = null  // 可空类型,编译通过
val length = nullable.length // 可能触发空指针,编译保报错

IDE 报错如下所示:
在这里插入图片描述
这个时候我们想 nullable.length 不报错可以:

  1. 当我们确定 nullable 不可能为空的时候,可以将 nullable 强转为不可空类型,如下所示:

    var nullable: String? = "Hello"
    // 不会报错了(自己已经知道了,这个 nullable 不可能为空)
    val length = nullable!!.length 
    
  2. 如果我们不确定 nullable 是否为空的时候,可以用 ?. 来实现安全访问,如下所示:

    var nullable: String? = "Hello"
    // 这种情况下如果 nullable 为空的话,那么返回的 length 也是空
    val length = nullable?.length
    // 这时候 length 的类型不是 Int,而是 Int?,所以可以写成下面这样
    val length: Int? = nullable?.length
    // 如果你想 length 的类型是 Int 的话,可以加个默认值,写成下面这样
    val length: Int = nullable?.length ?: 0  // 如果 nullable?.length 为空, 就返回0
    

2.2、空类型的继承关系

我们知道 Int 是 Number 的子类,所以通过下面的代码我们就可以知道 String 应该是 String? 的子类。

var a: Int = 2
var b: Number = 10.0

a = b // Type mismatch,报错
b = a // OK

var x: String = "Hello"
var y: String? = "World"

x = y // Type mismatch,报错
y = x // OK

2.3、Kotlin 空类型安全回顾

空类型安全小结

三、Kotlin 智能类型转换

3.1、智能类型转换例子

例子1:

我们先来写一个 Java 的类型转换:

// 定义一个接口
public interface Kotliner {
}
// 定义一个类 Person 实现 Kotliner 接口
public class Person implements Kotliner {
    public final String name;
    public final int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public static void main(String[] args) {
    	// 用子类的实例赋值给接口的引用
        Kotliner kotliner = new Person("Test", 20);
        // 这里已经判断了是不是 Person,但是下面还是要强制类型转换
        if (kotliner instanceof Person) {
            System.out.println(kotliner.name);  // 这样写报错
            System.out.println(((Person) kotliner).name);  // 正确写法
        }
    }
}

同样的代码在 Kotlin 中就可以实现智能类型转换,不需要强制类型转换:

val kotliner: Kotliner = Person("Test", 20)
if (kotliner is Person) {
	println((kotliner as Person).name)  // 不需要强转,可以智能转换,所以下面的写法就可以了
    println(kotliner.name)
}

例子2:

下面这段代码定义了一个 value, 类型是 String?,if 判断其不为空,所以在 if 判断这个括号里面,value 的类型会被智能转换成 String,当然出了括号,value 的类型就又是 String? 了。

var value: String? = null
value = "Test"
if (value != null) {
	// value: String?  ==>  String
	println(value.length)
}
// value: String?
...

3.2、不支持智能类型转换的情况

下面这种情况就不支持智能类型转换,因为这个公共变量很多地方都可以访问,所以我们在判断不为空之后,有可能别的线程又把 tag 改成了空,所以这种情况智能类型转换就失效了。

// 在 main 函数之外定义一个公共变量
var tag: String? = null

fun main() {
	if(tag != null) {
		// 有可能被改成空
	    println(tag.length)  // 报错,不支持智能类型转换
	}
}

3.3、几个建议

  • 尽可能使用 val 来声明不可变引用,让程序的含义更加清晰确定;
  • 尽可能减少函数对外部变量的访问;
  • 必要的时候曾创建局部变量指向外部变量,避免因它变化引起程序错误。

3.4、Kotlin 智能类型转换

智能类型转换小结

四、小结

本篇博客主要讲了 Kotlin 中的空类型安全智能类型转换,下一节我们讲 Kotin 中的表达式

五、源码

源码 已上传至 github,有需要可以直接下载。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Kotlin中,有两种类型转换方式:智能类型转换和强制类型转换智能类型转换是指在特定情况下,Kotlin编译器会自动推断变量的类型,无需显式进行类型转换。这种类型转换在编译期间完成,并且只适用于不同类型之间的子类型关系。例如,当将一个子类型的对象赋值给父类型的变量时,Kotlin会自动将其转换为父类型。 另一种类型转换方式是强制类型转换,使用as和as?操作符进行。强制类型转换需要显式指定要转换类型,并且在运行时进行类型检查和转换。当无法进行智能类型转换时,可以使用强制类型转换。需要注意的是,如果强制类型转换失败,会抛出ClassCastException异常。而使用as?操作符可以避免抛出异常,当转换失败时会返回null。 下面是一个示例代码,演示了如何在Kotlin中进行类型转换: ```kotlin fun main(args: Array<String>) { var a: Any = "1" var b: String = a as String // 强制将a转换为String类型 println(b.length) } ``` 在上述代码中,变量a的类型为Any,通过使用as操作符将其强制转换为String类型,然后可以访问String类型的属性和方法,如示例中的b.length。 总结起来,Kotlin中的类型转换智能类型转换和强制类型转换两种方式。智能类型转换适用于子类型关系,而强制类型转换使用as和as?操作符进行,可以在特殊情况下进行类型转换

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值