Kotlin空安全原理

前沿
可能又要闲置一段时间了,闲置的原因长的不知道从何说起,收拾收拾心情,整理下博客,不卑不亢,静下心来,梳理下知识点,写写博客记录下,就当是给自己放假啦,浮躁的人得静下心来,能力不够学习来凑!

kotlin空安全
被面试官问到kotlin空安全的原理,瞬间触碰到盲区了,自己用过kotlin也知道kotlin空安全的用法以及优点,就是没有想过它的原理是什么,然后卒。
回去特意查了下,kotlin对空字符串以及null的判断要比Java友好的多,相比较Java的TextUtils.isEmpty()方法,我们看看kotlin的校验空字符串的几个方法:

  • isNullOrEmpty: 为空指针或者字符串长度为0时返回true,非空字符串和可空字符串都可以调用。
  • isNullOrBlank: 为空指针、字符串长度为0或者全为空格时候返回true,非空字符串和可空字符串都可以调用。
  • isEmpty: 字符串长度为0时返回true,只有非空字符串的时候才可以调用。
  • isBlanK: 字符串长度为0或者全为空格时返回true,只有非空字符串才可以调用
  • isNotEmpty: 字符串长度大于0时返回true,只有非空字符串可以调用。
  • isNotBlank: 字符串长度大于0且不是全空格时返回true,只有非空字符串可以调用

定义可变变量
从上面的定义可以看出来,kotlin判断空值的时候要区分空串和非空字符串的,这是由于Kotlin的空安全概念,每个变量都可以定位为可以是空和不可以为空这两种。
定义可为空变量

 private var name:String?=null

定义不可为空变量

private var age = "18"

从这里好像看不出来有什么不同,接下来我们分别获取他们的长度:

//定义可为空变量
 val nameLength = name?.length
  val nameLength02 =name?.length?:0
 val nameLength01 = name!!.length
 
 //定义不为空变量  
  val ageLength=age.length

可以看到当不可以为空时,直接获取长度,而可为空时kotlin有几种比较常用的写法
第一种

val nameLength = name?.length
//类似Java
if(nameLength!=null)nameLength=name.length();
else nameLength=null;

第二种

val nameLength02 =name?.length?:0
如果为null的话我们可以自定义一个默认值而不是直接返回null

第三种

val nameLength01 = name!!.length
//!!表示强行放弃空安全判断默认值肯定不为空,当然遇到空值肯定闪退

看我们定义一个不可为空的value值来检验下:

在这里插入图片描述可以清楚看到 nameLength编译不通过,因为它存在为null的情况故编译器报错了。
nameLength01我们用 !! 修饰的即便存在null的情况,编译器不去检查编译也可以通过
nameLength02 我们通过 ?: 来给一个非null的默认值故通过编译
ageLength 为非空肯定没问题!

到这我们可以总结下kotlin的空安全概念

  1. 声明变量时,在类型后面加问号时,表示该变量可以为空;
  2. 调用变量方法时,在变量名后面加问号,表示如果为空就返回null;
  3. 当使用 ?: 运算符时表示如果变量为null 时返回我们运算符右边定义的值;
  4. 当使用 !! 运算符时,表示通知编译器不做非空校验,如果运行时发现变量为空时,抛出异常。

好了普及到这终于到重点了

kotlin 实现空安全判断的原理

因为这些都是关键字,只能从kotlin编译的.class文件下手了。
查看方式依次点击:Tools->Kotlin->Show Kotlin ByteCode
我写了三个测试类如下:

class TestDome {
    fun Test01(name:String){
        name.length
    }

    fun Test02(name:String?){
        name?.length
    }

    fun Test03(name:String?){
        name!!.length
    }

}

可以看到对应的Kotlin Bytecode

//方法Test01
  public final Test01(Ljava/lang/String;)V
    // annotable parameter count: 1 (visible)
    // annotable parameter count: 1 (invisible)
    @Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 0通过注解标示参数是否可以为null
   L0
    ALOAD 1
    LDC "name"
    INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull (Ljava/lang/Object;Ljava/lang/String;)V 如何不为null 则检查是否被复null值
   L1
    LINENUMBER 11 L1
    ALOAD 1
    INVOKEVIRTUAL java/lang/String.length ()I
    POP
   L2
    LINENUMBER 12 L2
    RETURN
   L3
    LOCALVARIABLE this Lcom/example/myapplication/kotin/TestDome; L0 L3 0
    LOCALVARIABLE name Ljava/lang/String; L0 L3 1
    MAXSTACK = 2
    MAXLOCALS = 2

//方法Test02
  public final Test02(Ljava/lang/String;)V
    // annotable parameter count: 1 (visible)
    // annotable parameter count: 1 (invisible)
    @Lorg/jetbrains/annotations/Nullable;() // invisible, parameter 0 表示可以为空值
   L0
    LINENUMBER 15 L0
    ALOAD 1
    DUP
    IFNULL L1 //如果是null 执行L1即Pop方法
    INVOKEVIRTUAL java/lang/String.length ()I
    POP
    GOTO L2
   L1
    POP
   L2
   L3
    LINENUMBER 16 L3
    RETURN
   L4
    LOCALVARIABLE this Lcom/example/myapplication/kotin/TestDome; L0 L4 0
    LOCALVARIABLE name Ljava/lang/String; L0 L4 1
    MAXSTACK = 2
    MAXLOCALS = 2
//方法Test03
  public final Test03(Ljava/lang/String;)V
    // annotable parameter count: 1 (visible)
    // annotable parameter count: 1 (invisible)
    @Lorg/jetbrains/annotations/Nullable;() // invisible, parameter 0
   L0
    LINENUMBER 19 L0
    ALOAD 1
    DUP
    IFNONNULL L1//如果不是null 执行L1即java/lang/String.length ()否则抛出异常
    INVOKESTATIC kotlin/jvm/internal/Intrinsics.throwNpe ()V
   L1
    INVOKEVIRTUAL java/lang/String.length ()I
    POP
   L2
    LINENUMBER 20 L2
    RETURN
   L3
    LOCALVARIABLE this Lcom/example/myapplication/kotin/TestDome; L0 L3 0
    LOCALVARIABLE name Ljava/lang/String; L0 L3 1
    MAXSTACK = 2
    MAXLOCALS = 2

仔细对比字节码的朋友会发现
Test01方法入口下面的注解是:

@Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 0
可以看到是NotNull

而Test02、Test03是:

@Lorg/jetbrains/annotations/Nullable;() // invisible, parameter 0
可以看到是Nullable

那对于Test01方法注 解是 NotNull我们传入一个null值编译器是又如何知道报错的呢?

kotlin编译器内部调用了是否为null的检查,这就是为什么我们传入null的时候会编译报错
INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull (Ljava/lang/Object;Ljava/lang/String;)V

而Test02、Test03方法是不会执行这个检查的,但是Test02和Test03也是有区别的:
Test02:

LINENUMBER 15 L0
ALOAD 1
DUP
IFNULL L1
INVOKEVIRTUAL java/lang/String.length ()I
POP
GOTO L2
L1
POP
L2
L3
LINENUMBER 16 L3
RETURN

可以看出如果是null的话直接执行POP而不去执行String.length()方法;

Test03方法多了个异常抛出的方法

INVOKESTATIC kotlin/jvm/internal/Intrinsics.throwNpe ()V

也就是当name为null时直接抛出异常。

到这通过查看三个方法的字节码,我们可以总结下Kotlin空安全原理:

  1. 首先通过注解 @Lorg/jetbrains/annotations/NotNull;和@Lorg/jetbrains/annotations/Nullable;来向编译器标示参数是否为空,如果不为空则通过 INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull (Ljava/lang/Object;Ljava/lang/String;)来进行检查,此时如果我们给个空值则编译器出现报错提示。
  2. 对用使用 ?. 操作符号kotlin会判断是否为null 如果不为null执行对应的逻辑,如果为null则什么也不执行(此时的默认结果也是null)
  3. 对用使用 !! 操作符号 Kotlin 同样会执行null判断如果不为null 则执行对应的逻辑,如果为null 则抛出异常,即执行 INVOKESTATIC kotlin/jvm/internal/Intrinsics.throwNpe ()
  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
Kotlin是一种现代化的编程语言,它与Java具有很好的兼容性。Kotlin的兼容原理主要包括以下几个方面: 1. Kotlin与Java代码互操作:Kotlin可以与Java代码无缝地进行互操作。这意味着你可以在Kotlin代码中调用Java类和方法,也可以在Java代码中调用Kotlin类和方法。Kotlin编译器会将Kotlin代码转换为与Java兼容的字节码,使得Kotlin代码可以在Java虚拟机(JVM)上运行。 2. Kotlin标准库:Kotlin提供了一个丰富的标准库,其中包含了许多与Java标准库相似的功能。这使得Kotlin开发者可以方便地使用Java标准库中的类和方法,同时也可以使用Kotlin特有的扩展函数和其他功能。 3. Null安全性:Kotlin引入了安全性的概念,可以在编译时捕获可能导致指针异常的问题。这对于与Java代码的兼容性非常重要,因为Java中的对象可以为null,而Kotlin中的对象默认是非的。Kotlin使用可类型和安全调用操作符来处理可能为的值。 4. Java框架和库的支持:Kotlin可以与许多流行的Java框架和库无缝集成,如Spring、Hibernate、Android等。Kotlin提供了一些特性和语法糖,使得与这些框架和库的使用更加简洁和安全。 5. 扩展函数和属性:Kotlin引入了扩展函数和属性的概念,可以为已有的Java类添加新的函数和属性。这使得Kotlin代码可以更加灵活地与Java代码进行互操作,而无需修改Java类的源代码。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值