Kotlin空安全原理

编程入门 行业动态 更新时间:2024-10-14 22:13:42

Kotlin空安全<a href=https://www.elefans.com/category/jswz/34/1770123.html style=原理"/>

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?.lengthval nameLength02 =name?.length?:0val 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

//方法Test01public final Test01(Ljava/lang/String;)V// annotable parameter count: 1 (visible)// annotable parameter count: 1 (invisible)@Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 0通过注解标示参数是否可以为nullL0ALOAD 1LDC "name"INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull (Ljava/lang/Object;Ljava/lang/String;)V 如何不为null 则检查是否被复null值L1LINENUMBER 11 L1ALOAD 1INVOKEVIRTUAL java/lang/String.length ()IPOPL2LINENUMBER 12 L2RETURNL3LOCALVARIABLE this Lcom/example/myapplication/kotin/TestDome; L0 L3 0LOCALVARIABLE name Ljava/lang/String; L0 L3 1MAXSTACK = 2MAXLOCALS = 2//方法Test02public final Test02(Ljava/lang/String;)V// annotable parameter count: 1 (visible)// annotable parameter count: 1 (invisible)@Lorg/jetbrains/annotations/Nullable;() // invisible, parameter 0 表示可以为空值L0LINENUMBER 15 L0ALOAD 1DUPIFNULL L1 //如果是null 执行L1即Pop方法INVOKEVIRTUAL java/lang/String.length ()IPOPGOTO L2L1POPL2L3LINENUMBER 16 L3RETURNL4LOCALVARIABLE this Lcom/example/myapplication/kotin/TestDome; L0 L4 0LOCALVARIABLE name Ljava/lang/String; L0 L4 1MAXSTACK = 2MAXLOCALS = 2
//方法Test03public final Test03(Ljava/lang/String;)V// annotable parameter count: 1 (visible)// annotable parameter count: 1 (invisible)@Lorg/jetbrains/annotations/Nullable;() // invisible, parameter 0L0LINENUMBER 19 L0ALOAD 1DUPIFNONNULL L1//如果不是null 执行L1即java/lang/String.length ()否则抛出异常INVOKESTATIC kotlin/jvm/internal/Intrinsics.throwNpe ()VL1INVOKEVIRTUAL java/lang/String.length ()IPOPL2LINENUMBER 20 L2RETURNL3LOCALVARIABLE this Lcom/example/myapplication/kotin/TestDome; L0 L3 0LOCALVARIABLE name Ljava/lang/String; L0 L3 1MAXSTACK = 2MAXLOCALS = 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 ()

更多推荐

Kotlin空安全原理

本文发布于:2024-02-12 19:16:25,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1689053.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:原理   Kotlin

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!