Kotlin 学习教程之类型系统和智能类型转换(二)

说在前面

从上一篇我们了解了 kotlin 这门语言,以及通过 IntelliJ IDEA 和 AndroidStudio 开发工具创建了 kotlin 项目并运行了 “hello world” 程序,在这一篇,我们将来学习 kotlin的数据类型系统,以及各种类型之间的转换。

1. Java 类型系统
image

由上图可知:在 Java 中,类型系统由8种基本类型,6种引用类型以及一种空特殊的空引用类型。

  • 基本类型:byte,char,short,long,float,double,int,boolean

  • 引用类型:

    • 类:class

    • 接口:interface

    • 数组:array

    • 参数化类型:泛型

    • 注解:Annotation

    • 枚举:enumeration

  • 空引用:null

基本数据类型和引用数据类型在创建的时候,内存的存储方式区别:

  • 基本数据类型:在被创建时,在栈上给其划分一块内存,将数值 直接存储在栈上(性能高);

  • 引用数据类型:在被创建时,首先在栈上给其引用(句柄)分配 一块内存,而对象的具体信息存储在堆内存上,然后由栈上面 的引用指向堆中对象的地址。

2.kotlin 类型系统

在 kotlin 中,将类型系统根据数据是否可空分为了可空类型和不可空类型。可空类型能够在编译程序的时候进行类型检查,以提前发现并解决问题,大大的降低了出现空指针的情况。

2.1 不可空类型

kotlin 中不可空的数字类型对应了 Java 中的原始类型,但是写法却 不一样:

  • Kotlin中的数字类型与 Java 原始的数字类型
Snipaste_2020-02-17_10-31-55.png
// 声明Int 型
val age:Int=20
//声明Long 型
val along:Long=12368172397127391
//声明 Float 型
val aFloat:Float=2.0F
//声明 double 型
val aDouble:Double=3.0
//声明 Short 型
val aShort:Short=127
// 声明Byte 型
val maxByte: Byte = Byte.MAX_VALUE
//声明Boolean
val aBoolean: Boolean = true

以上都是不可空的数字类型,在声明变量的时候都给它们赋了值,但是如果我们不给它赋值或者赋值为空,则编译器会显示错误,提醒我们必须要初始化该数字类型的值。

Snipaste_2020-02-17_10-31-55.png
Snipaste_2020-02-17_10-31-55.png
  • Kotlin中可空数字类型与 Java 中装箱数字类型


    Snipaste_2020-02-17_10-31-55.png

    Snipaste_2020-02-17_10-31-55.png
2.2 可空类型

在Java 开发中,经常会遇到空指针的问题,那么能不能在编译的时候提前发现错误并进行代码修复呢?kotlin中出现了可空类型以解决这个痛点。我们以如下输出字符串str的长度代码为例:

  • kotlin中:
val str:String? ="hello world"
fun getLength():Int{
    return str?.length?:0
}
fun main(args: Array) {
   println("str字符串的长度为:${getLength()}")
}
  • Java代码:
public class helloword {
    static String str = "hello world";
    public static void main(String[] args) {
        System.out.print("str 字符串的长度为:" + getLength());

    }

    public static int getLength() {
        if (str != null) {
            return str.length();
        } else {
            return 0;
        }
    }
}

在kotlin 代码中 str?.length?:0 就是 kotlin中常用的 Elvis表达式,它的意思是如果str为不空,那就返回 str.length的值,否则返回0。同样的需求,不一样量的代码,kotlin是不是显得更加精简全面呢?显然是的。

2.3 安全操作符

(1)安全调用符:"?."

val str:String? ="hello world"
fun main(args: Array) {
   // 方式一:
    if (str != null) {
        println(str.length)
    }
    // 方式二:
    println(str?.length)
}

我们知道,在程序中,不能使用可空的对象直接调用其属性或者方法,否则会直接报错,在Java 中也会出现空指针异常。在以上代码中,在保证程序的正常执行的情况下,方式一和方式二需求一样,但是方式二使用了安全调用符 ?.是得代码更加的简洁。程序只有在str不为空的情况下才会执行 str.length的方法。

(2)Elvis运算符“?:”

在前面例子中 str?.length?:0 就使用了Elvis运算符“?:”,同理只有str不为空的情况下才会执行 str.length的方法

(3)非空断言“!!”

Kotlin中提供了断言操作符“!!”,它表示已经确定该可空对象不为空且直接调用其属性或方法。该操作符需要谨慎使用,因为一旦遇到了该对象为空的时候,则会导致空指针异常。代码及结果如下:

Snipaste_2020-02-17_10-31-55.png
3.类型检测和智能类型转换
3.1 is 和 !is 运算符

is运算符是用来检测对象A是否与特定的类型X兼容(此对象A是X类型或者派生于X类型)

Snipaste_2020-02-17_10-31-55.png
3.2 Java 和kotlin中的类型转换

例子:

  • 现有一个子类,一个父类,子类和父类各自拥有一个方法

  • 需要实现父类调用子类的方法 以及子类调用父类的方法打印输出"hello kotlin"

(1)Java 代码实现

Snipaste_2020-02-17_10-31-55.png

(2)kotlin代码实现


Snipaste_2020-02-17_10-31-55.png

对比以上代码可知:Java 中父类在调用子类方法获取 “kotlin”字符串的时候,编译器中进行了强制类型转换,而kotlin 代码中,父类直接调用了子类的getKotlin(),并没有进行强制类型转换,这是因为编译器已经知道它该父类本来就是子类的实例,无需再进行强转。

3.3 kotlin中智能类型转换

在kotlin中,使用 as 进行引用类型的显式类型转换类型转换,但如果类型转换失败会出现类型转换失败的异常,使用 as?运算符进行智能类型转换,当转换失败的时候直接返回null,代码如下:

fun main(args: Array) {
    val parent: Parent = Parent()
    val child: Child? =parent as? Child
    println(child?.getKotlin())

}
open class Parent{
    fun getHello():String{
        return "hello"
    }
}
class Child : Parent() {
    fun getKotlin(): String {
        return "kotlin"
    }
}

以上代码,父类转换为子类并调用其方法,会出现类型转换失败的异常,但是使用了as?运算符,会直接输出null而避免了异常。

你可能感兴趣的:(Kotlin 学习教程之类型系统和智能类型转换(二))