美文网首页Kotlin
Kotlin 中空类型判断原理分析

Kotlin 中空类型判断原理分析

作者: 两三行代码 | 来源:发表于2020-04-21 23:43 被阅读0次

     在Java编程语言中,NullPointerException或简称为NPE是最常见的异常,也称为《十亿美元的错误》
    ,使javaer深受其苦。如果在代码中到处判空则显得代码过于丑陋,代码量也会疾速膨胀。
     基于此,作为后来者的Kotlin则吸取了上述教训,在设计之初就将消除来自代码空引用的危险作为宗旨。
     在Kotlin中为解决空类型安全问题,引入了安全调用操作符,写做?. 如下所示:

    var a = "Kotlin" //  1
    var b: String? = null // 2
    println(b?.length) //3
    println(a?.length) // 4无需安全调用
    

    对以上1处 为非空类型 其等价于以下示例 且不可对非空类型置为null

    var a: String = "abc"
    a = null // 编译错误
    

    对以上2处 则表示为字符串的可空类型 默认为null 在3处调用处表示在b为非空情况下打印获取其长度

    以上为对安全调用操作符简单使用讲解,详细描述可参考Kotlin 空安全

    现在我们来思考一下?.背后的实现原理,它到底是如果实现空安全的呢?

    Java和Kotlin都是基于JVM的编程语言,共同遵循JVM规范,试想在Java中的空类型判断都是如下所示:

    if(b!=null){
    //do something work
    }else{
    //do something work
    }
    

    那么Kotlin在底层实现上是否也是如此?或者说?.安全调用符是对上述判断的封装呢?让我们来撸段代码来一探究竟:

    class DemoActivityK : AppCompatActivity() {
    
        var str1: String?  = null
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.demo_k)
            Logger.i("len ${str1?.length}")
        }
    }
    

    在代码编译后借助Bytecode Viewer 查看DemoActivityK.class文件即可,以下摘抄关键部分:

    protected void onCreate(@Nullable final Bundle savedInstanceState) {
           super.onCreate(savedInstanceState);
           this.setContentView(R$layout.demo_k);
           final StringBuilder append = new StringBuilder().append("len ");
           final String str1 = this.str1;
           Logger.i(append.append((str1 != null) ? Integer.valueOf(str1.length()) : null).toString(), new Object[0]);
       }
    

    从上述代码中可以看出来对str1作了str1!=null的判断,然后获取字符串长度,和Java传统实现思路是一样的写法,只不过是现在Kotlin通过?.语法简化了实现方式。
    进一步扩展查看以下对应的字节码部分

       L4 {
                 new java/lang/StringBuilder
                 dup
                 invokespecial java/lang/StringBuilder.<init>()V
                 ldc "len " (java.lang.String)
                 invokevirtual java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lang/StringBuilder;
                 aload0 // reference to self
                 getfield com/khronos/modular1/kotlin/DemoActivityK.str1:java.lang.String //1
                 dup //2
                 ifnull L5   // 3
                 invokevirtual java/lang/String.length()I
                 invokestatic java/lang/Integer.valueOf(I)Ljava/lang/Integer;
                 goto L6
             }
             L5 {
                 f_new (Locals[2]: com/khronos/modular1/kotlin/DemoActivityK, android/os/Bundle) (Stack[2]: java/lang/StringBuilder, java/lang/String)
                 pop
                 aconst_null
             }
             L6 {
                 f_new (Locals[2]: com/khronos/modular1/kotlin/DemoActivityK, android/os/Bundle) (Stack[2]: java/lang/StringBuilder, java/lang/Integer)
                 invokevirtual java/lang/StringBuilder.append(Ljava/lang/Object;)Ljava/lang/StringBuilder;
                 invokevirtual java/lang/StringBuilder.toString()Ljava/lang/String;
                 iconst_0
                 anewarray java/lang/Object
                 invokestatic com/orhanobut/logger/Logger.i(Ljava/lang/String;[Ljava/lang/Object;)V
             }
    

    可以看见上述 //1 //2 //3处为读取str1值写入栈顶 然后拷贝栈顶值再此压如栈顶 在 3处判断如果为null则走L5字节码片段,否则后续获取字符串长度 然后跳转L6处字节码片段。

    至此我们已经对Kotlin安全调用符?. 已经有了一个比较完整的认识。其实Kotlin和Java都是基于JVM的编程语言,Kotlin的许多语法的底层实现原理可以类比Java的实现思路,然后查看其字节码和类文件实现就能一探究竟。

    相关文章

      网友评论

        本文标题:Kotlin 中空类型判断原理分析

        本文链接:https://www.haomeiwen.com/subject/khtvihtx.html