反編譯扒皮kotlin系列(一)

寫做本文的目的

kotlin雖然不是java的語法糖,但在做用上確實就是個語法糖,學起來雖然輕鬆,可是有些概念不常用容易埋坑, 多看看kotlin反編譯之後的代碼 能夠加深對 語法糖的 理解。也能夠避免用java的寫法來寫kotlin。熟悉了之後能夠更輕鬆自如的寫kotlin味道的kotlin代碼。java

const val 與 val

object MyObject {
    const val t1 = 1
    val t2 = 2
}

複製代碼

來看看反編譯之後的代碼es6

public final class MyObject {
   public static final int t1 = 1;
   private static final int t2 = 2;
   public static final MyObject INSTANCE;

   public final int getT2() {
      return t2;
   }

   private MyObject() {
   }

   static {
      MyObject var0 = new MyObject();
      INSTANCE = var0;
      t2 = 2;
   }
}
複製代碼

從代碼中能夠看到 訪問t1 的時候 是直接經過 field來訪問 訪問t2 的時候 就是用的 方法了。bash

因此總結下區別:閉包

const val 是public的 val 是private的,訪問效率上 val 要低一些,const val 要高一些。 由於訪問val是經過方法,要有一次方法調用。而const val 則是直接訪問field 效率更高函數

== 與 ===

實話說 這個設計我以爲是一個很是失敗的設計,都快和js同樣了。但既然kotlin這樣設計了 咱們仍是看看爲何這樣設計性能

fun main() {
    var user1 = User3("wuyue", "t3")
    var user2 = user1.copy()
    println(user1 == user2)
    println(user1 === user2)

}
data class User3(var username: String, var password: String?)
複製代碼

他的執行結果:ui

在java中顯然是沒有=== 這個操做符的。可是kotlin中。 上面的代碼 我直接解釋成this

== 在koltin中表明 對象中的field 是否相等。 === 表明引用是否相等。spa

來反編譯看看設計

看下copy函數作了啥

看到這應該能明白kotlin的 copy函數 其實就是從新new了一個對象 固然是淺拷貝。

==走的 就是下面這個函數

顯然這個eqauls 就是user3的equals了

看到這你應該就能明白kotlin中的 == 與 === 的區別是哪來的了。 同時也能夠知道 data class 這種寫法

會自動根據咱們設定的field來幫咱們生成equals方法。

kotlin中的解構

package com.wuyue

data class Response(var code:Int,var message:String)

fun execute():Response{
    val code=200
    var message="ok"
    return Response(code,message)
}

fun main()
{
    val(code,message)= execute()
    println(code)
    println(message)
}

複製代碼

這個代碼相信不少人都看得懂, 看main函數裏 的第一行代碼 這樣的寫法其實和es6中的解構實際上是差很少的 也就是說 咱們能夠在一個函數調用中 返回多個值 ,這樣的寫法比咱們不停的get出來返回值 要高效的多。 可是注意了這裏和go語言中的函數多返回值是不同的。

咱們來看看kotlin中 是如何實現解構的

首先能夠看一下:

data class 的寫法 生成的bean代碼 中 是多了這2個函數的。

而後看看調用時的寫法

不用解釋了吧。。。因此看到這 你應該能夠理解這句話: kotlin雖然不是java的語法糖,但在做用上確實是無限接近於語法糖的做用的

kotlin中神奇的擴展函數

fun main() {

    var a = "hello world"
    println(a.doubleToString())
}

fun String.doubleToString(): String {
    return this.toString() + "__" + this.toString()
}

複製代碼

初學kotlin的都以爲 擴展函數很神奇,好比上面的代碼。 擴展了string的函數 增長一個doubleToString的函數, 函數的做用我就不寫了,你們一看就懂。

如今來反編譯看看 這究竟是咋實現的

嗯 愈來愈像語法糖了。

inline 函數

仍是上面的例子

inline fun String.doubleToString2(): String {
    return this.toString() + "__" + this.toString()
}


fun main() {

    var a = "hello world"
    println(a.doubleToString())
    println(a.doubleToString2())

}

fun String.doubleToString(): String {
    return this.toString() + "__" + this.toString()
}

複製代碼

你看我新增了一個內聯函數,這東西幹啥的?傳說能提升性能?反編譯看一看

一眼就看出來,加上inline關鍵字的地方 在實際函數調用時 其實就是直接調用了inline函數體裏面的語句

而沒有直接調用函數自己,相對而言能夠節省一次函數調用。可是也就僅此而已了。 我的認爲少一次函數調用出棧入棧 其實並提升不了多少效率。

反而的這樣還會帶來代碼膨脹。假設你inline函數裏面語句很是多,那麼你若是在不少地方都調用了這個inline函數 可想而知 你調用的地方就會多出來很是多的代碼。 代碼膨脹的速度是飛快的。

kotlin支持 函數做爲參數的真相

這個又是一個相似於js的功能。咱們來看看kotlin實際是怎麼作的

class View {
    interface OnClickListener {
        fun onClick(view: View)
    }

    fun setOnClickListener(listener: (View) -> Unit) {
    }
}


fun main() {

    var view = View()
    view.setOnClickListener {
        onClick(view)
    }

}

fun onClick(view: View) {
    println("被點擊")
}
複製代碼

很像js的閉包了,java中就不能夠傳遞一個函數做爲一個參數,可是kotlin能夠, 那咱們看看是怎麼作的

首先反編譯能夠看出來 其實在定義的時候 仍是interface在起做用的。

咱們最終調用的時候 也能夠看出來 仍是遵循的java的規範 傳遞的是一個實際的對象。並非函數。

這裏你們有能夠試試 在回調函數這邊增長個inline關鍵字,看看會發生什麼,這裏就不演示了

init函數

fun main() {

    var p1 = Persont()

}

class Persont constructor() {

    init {
        println("111")
    }

    init {
        println("222")
    }

}
複製代碼

運行之後結果以下:

反編譯看一看:

因此說這個地方的init函數 無非就是 當你在kotlin中使用了主構造器的時候 把你的init裏面的代碼 按照順序放到構造函數裏面,其餘沒啥。 爲何要這麼作? 固然是由於主構造器的寫法沒有方法體,因此須要這麼寫,僅此而已。

相關文章
相關標籤/搜索