Java转Kotlin:空类型安全与平台类型

524 阅读3分钟

1 非空类型与可空类型

1.1 非空类型

为了让代码更安全,Kotlin相比Java新增了非空类型可空类型的概念。

普通的String类型在Kotlin中属于非空类型non-null type String,不能复制为null

fun test0() {
    val nonNull: String = ""
//    nonNull = null
    var length1 = nonNull.length
}

我们将赋值为null的代码行注释,并直接读取nonNulllength,因为nonNull是非空类型,所以读取length的代码是完全安全的,绝对不会出现空指针异常。这对提升代码安全性大有益处。

1.2 可空类型

如果我们需要一个可空类型呢?

请使用String?类型

如上图,可空类型可以被赋值为null。但是当我们尝试直接去读取nullable变量的length属性的时候,编译器开始报错,如下图。

编译器告诉我们:String?类型只能进行安全调用?.或者对变量进行强行非空断言后调用非空类型的属性和方法。

1.2.1 安全调用

对上述代码进行更改,按照提示采用安全调用,编译通过了。但此时的length2变量自动推导的类型是Int?而不是Int,如下图。

可知,当可空类型变量nullablenull时,length2: Int?也是null,且此时读取length属性的操作不会进行,保证了代码的安全性。

1.2.2 强行非空断言

当我们确定可空变量的值不是null时,我们可以使用!!.对变量进行强行非空断言,然后调用属性或方法。这是非常不推荐的危险操作!除非必要,不要使用,养成良好的编程习惯。

注意!经过强行非空断言的代码行,length2Int类型,而不是Int?,如下图。

1.2.3 elvis表达式

面对可空类型,我们使用的最多的当然是安全调用,这里需要介绍elvis表达式。

elvis表达式用在安全调用的场景中,当安全调用的可空类型变量是null时,elvis表达式将输出?:后面的值,充当替补值。例如上图中的length2将被赋值为0

当然,此时无论nullable是否为空,length2都能得到一个Int值,因此,length2将被推断为Int类型,如下图,这很好理解。

1.3 String与String?的关系

如图可见,将String类型变量赋值给String?类型变量是OK的,但是将String?类型变量赋值给String类型变量是NOT OK的。根据里氏替换原则,可知,String?是String的父类

2 平台类型

我们在Java中定义一个简单的Person类:

//Java
package imooc.chapter_4;

public class Person {
    public String name;
    public String gender;

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }
}

然后我们在Kotlin中创建一个Person类的对象bob

//Kotlin
package imooc.chapter_4

fun main() {
    val bob = Person("Bob")
    var name = bob.getName()
    var gender = bob.getGender()
    var length = gender?.length
}

此时,变量namegender的推导类型为String!,如下图。

String!类型即为平台类型

此时,bob对象的gender字段还未set,故为null,但是Kotlin不知道,因此直接如图调用将会空指针报错。

此例中的平台为Java,故该String!为Java中的String类。平台类型为空与否,是否支持为空都是Kotlin无法确定的,因此需要谨慎使用。可以考虑安全访问和elvis表达式。

总结