欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Kotlin標(biāo)準(zhǔn)函數(shù)與靜態(tài)方法基礎(chǔ)知識詳解

 更新時間:2022年11月24日 10:52:00   作者:發(fā)飆的蝸牛YR  
Kotlin中的標(biāo)準(zhǔn)函數(shù)指的是Standard.kt文件中定義的函數(shù),任何Kotlin代碼都可以自由地調(diào)用所有的標(biāo)準(zhǔn)函數(shù)。例如let這個標(biāo)準(zhǔn)函數(shù),他的主要作用就是配合?.操作符來進(jìn)行輔助判空處理

標(biāo)準(zhǔn)函數(shù)with與run和apply with函數(shù)

with函數(shù)

接收兩個參數(shù):第一個參數(shù)可以是任意類型的對象,第二個參數(shù)是一個Lambda表達(dá)式。with函數(shù)會在Lambda表達(dá)式中提供第一個參數(shù)對象的上下文,并使用Lambda表達(dá)式中的最后一行代碼作為返回值返回。

示例代碼如下:

val result=with(obj){
//這里是obj的上下文
"value"http://with函數(shù)的返回值
}

那么這個函數(shù)有什么作用呢?它可以在連續(xù)調(diào)用同一個對象的多個方法時讓代碼變得更加精簡,下面我們來看一個具體的例子。

比如有一個水果列表,現(xiàn)在我們想吃完所有的水果,并將結(jié)果打印出來,可以這樣寫

    val list= listOf("Apple","Banana","Orange","Pear","Grape")
        val builder=StringBuilder()
        builder.append("Start eating fruits.\n")
        for(fruit in list){
            builder.append(fruit).append("\n")
        }
        builder.append("Ate all fruits.")
        val result=builder.toString()
        println(result)

這段代碼的邏輯很簡單,就是使用StringBuilder來構(gòu)建吃水果的字符串,最后將結(jié)果打印出來

打印結(jié)果為:

觀察上述代碼,你會發(fā)現(xiàn)我們連續(xù)調(diào)用了很多次builder對象的方法。其實(shí)這個時候就可以考慮使用with函數(shù)來讓代碼變得更加精簡,如下所示:

        val list= listOf("Apple","Banana","Orange","Pear","Grape")
        val result= with(StringBuilder()){
            append("Start eating fruits.\n")
            for(fruit in list){
                append(fruit).append("\n")
            }
            append("Ate all fruits.")
            toString()
        }
        println(result)

首先我們給with函數(shù)的第一個參數(shù)傳入一個StringBuilder對象,那么接下來整個Lambda表達(dá)式的上下文就會是這個StringBuilder對象。于是我們在Lambda表達(dá)式中就不用再像剛才那樣調(diào)用builder.append()和builder.toString()方法了,而是可以直接調(diào)用append()和toString()方法。Lambda表達(dá)式最后一行代碼會作為with函數(shù)的返回值返回,最終我們將結(jié)果打印出來。

雖然兩段代碼結(jié)果一樣,但是明顯第二段代碼的寫法更加簡潔一些,這就是with函數(shù)的作用。

run函數(shù)

run函數(shù)的用法和使用場景其實(shí)和with函數(shù)時非常類似的,只是稍微做了一些語法改動而已。首先run函數(shù)是不能直接調(diào)用的,而是一定要調(diào)用某個對象的run函數(shù)才行;其次run函數(shù)只接收一個Lambda參數(shù),并且會在Lambda表達(dá)式中提供調(diào)用對象的上下文。其他方面和with函數(shù)一樣,包括也會使用Lambda表達(dá)式最后一行作為返回值返回。示例代碼如下:

val result=obj.run{
//這里是obj的上下文
"value"http://run函數(shù)的返回值
}

那么現(xiàn)在我們就可以使用run函數(shù)來修改一下吃水果的這段代碼,如下所示

     val list= listOf("Apple","Banana","Orange","Pear","Grape")
        val result=StringBuilder().run{
            append("Start eating fruits.\n")
            for(fruit in list){
                append(fruit).append("\n")
            }
            append("Ate all fruits.")
            toString()
        }
        println(result)

總體來說變化很小,只是將調(diào)用with函數(shù)并傳入StringBuilder對象改成了調(diào)用StringBuilder對象的run方法,其他沒什么區(qū)別,這兩段代碼最終的執(zhí)行結(jié)果是完全相同的。

apply函數(shù)

apply函數(shù)和run函數(shù)也是極其相似的,都是在某個對象上調(diào)用,并且接收一個Lambda參數(shù),也會在Lambda表達(dá)式中提供調(diào)用對象的上下文,但是apply函數(shù)無法指定返回值,而是會自動返回調(diào)用對象本身。示例如下:

val result=obj.apply{
//這里是obj的上下文
}
//result==obj

那么現(xiàn)在我們再使用apply函數(shù)來修改一下吃水果的這段代碼

     val list= listOf("Apple","Banana","Orange","Pear","Grape")
        val result=StringBuilder().apply{
            append("Start eating fruits.\n")
            for(fruit in list){
                append(fruit).append("\n")
            }
            append("Ate all fruits.")
        }
        println(result.toString())

由于apply函數(shù)無法指定返回值,只能返回調(diào)用對象本身,因此result實(shí)際上是一個StringBuilder對象,所以我們在最后打印的時候還要調(diào)用它的toString()方法才行。這段代碼的執(zhí)行結(jié)果和前面兩段仍然完全相同的。

其實(shí)with、run和apply這幾個函數(shù)的用法和使用場景是非常類似的。在大多數(shù)情況下,可以相互轉(zhuǎn)換。

例如我們啟動Activity的時候

val intent=Intent(this,SecondActivity::class.java)
intent.putExtra("param1","data1")
intent.putExtra("param2","data2")
startActivity(intent)

這里每傳遞一個參數(shù)就會調(diào)用一次intent.putExtra()方法,如果要傳遞10個參數(shù),那就得調(diào)用10次。對于這種情況,我們就可以使用標(biāo)準(zhǔn)函數(shù)來對代碼進(jìn)行精簡,如下所示

val intent=Intent(this,SecondActivity::class.java).apply{
intent.putExtra("param1","data1")
intent.putExtra("param2","data2")
}
startActivity(intent)

可以看到,由于Lambda表達(dá)式中的上下文就是Intent對象,所以我們不需要調(diào)用intent.putExtra()方法,而是直接調(diào)用putExtra()方法就可以了。傳遞的參數(shù)越多,這種寫法優(yōu)勢也就越明顯。

定義靜態(tài)方法

靜態(tài)方法再某些編程語言里面又叫做類方法,指的就是那種不需要創(chuàng)建實(shí)例就能調(diào)用的方法,所有主流的編程語言都會支持靜態(tài)方法這個特性。

在java中定義一個靜態(tài)方法,只需要在方法上聲明一個static關(guān)鍵字就可以了,如下所示:

public class Util{
public static void doAction(){
System.out.printlin("do action")
}
}

上述代碼中的doAction()方法就是一個靜態(tài)方法。調(diào)用靜態(tài)方法并不需要創(chuàng)建類的實(shí)例,而是可以直接以Util.doAction()這種寫法調(diào)用。因而靜態(tài)方法非常適合用于編寫一些工具類的功能,因為工具類通常沒有創(chuàng)建實(shí)例的必要,基本上是全局通用的。

和大多數(shù)主流編程語言不同的是,kotlin卻極度弱化了靜態(tài)方法這個概念,想要在Kotlin中定義一個靜態(tài)方法反倒不是那么容易。

因為Kotlin提供了比靜態(tài)方法更好用的語法特性,那就是單例類

object Util{
fun doAction(){
println("do action")
}
}

雖然這里的doAction不是靜態(tài)方法,但是我們?nèi)匀豢梢允褂肬til.doAction()方式來調(diào)用,這就是單例類所帶來的便利。

不過,使用單例類的寫法會將整個類中所有方法全部變成類似于靜態(tài)方法的調(diào)用方式,而如果我們只是希望讓類中的某一個方法變成靜態(tài)方法的調(diào)用方式該怎么辦呢?這個時候就可以使用companion object了,示例如下:

class Util{
fun doAction1(){
println("do action1")
}
companion object{
fun doAction2(){
println("do action2")
}
}
}

首先我們將Util從單例類改成一個普通類,然后在類中直接定義一個doAction1()方法,又在companion object中定義了一個doAction2()方法?,F(xiàn)在兩個方法就有了本質(zhì)的區(qū)別,因為doAction1()方法是一定要先創(chuàng)建Util類的實(shí)例才能調(diào)用的,而doAction2()方法可以直接使用Util.doAction2()的方式調(diào)用。

不過,doAction2()方法其實(shí)也不是靜態(tài)方法,companion object這個關(guān)鍵字實(shí)際上會在Util類的內(nèi)部創(chuàng)建一個伴生類,而doAction2()方法就是定義在這個伴生類里面的實(shí)例方法。只是Kotlin會保證Util類始終只會存在一個伴生類對象,因此調(diào)用Util.doAction2()方法實(shí)際上就是調(diào)用了Util類中伴生對象的doAction2()方法。

編譯成字節(jié)碼結(jié)果如下:

public final class Util {
   public static final Util.Companion Companion = new Util.Companion((DefaultConstructorMarker)null);
   public final void doAction1() {
      String var1 = "do action1";
      boolean var2 = false;
      System.out.println(var1);
   }
   @Metadata(
      mv = {1, 1, 16},
      bv = {1, 0, 3},
      k = 1,
      d1 = {"\u0000\u0012\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0010\u0002\n\u0000\b\u0086\u0003\u0018\u00002\u00020\u0001B\u0007\b\u0002¢\u0006\u0002\u0010\u0002J\u0006\u0010\u0003\u001a\u00020\u0004¨\u0006\u0005"},
      d2 = {"Ltest/Util$Companion;", "", "()V", "doAction2", "", "kotlin01"}
   )
   public static final class Companion {
      public final void doAction2() {
         String var1 = "do action2";
         boolean var2 = false;
         System.out.println(var1);
      }
      private Companion() {
      }
      // $FF: synthetic method
      public Companion(DefaultConstructorMarker $constructor_marker) {
         this();
      }
   }
}

由此看出,Kotlin中確實(shí)沒有直接定義靜態(tài)方法的關(guān)鍵字,但是提供了一些語法特性來支撐類似于靜態(tài)方法調(diào)用的寫法,這些語法特性基本上可以 滿足我們平時的開發(fā)需求了。

如果需要真正的靜態(tài)方法,Kotlin提供了兩種實(shí)現(xiàn)方式:注解和頂層方法。

先來看注解,前面的單例類和companion object都只是在語法的形式上模仿了靜態(tài)方法的調(diào)用方式,實(shí)際上他們都不是真正的靜態(tài)方法。因此如果你在Java中以靜態(tài)方法的形式去調(diào)用的話,你會發(fā)現(xiàn)這些方法并不存在。而如果我們給單例類或companion object中的方法加上@JvmStatic注解,那么Kotlin編譯器就會將這些方法編譯成真正的靜態(tài)方法,如下所示:

class Util{
    fun doAction1(){
        println("do action1")
    }
    companion object{
        @JvmStatic
        fun doAction2(){
            println("do action2")
        }
    }
}

編譯成字節(jié)碼,此時doAction2()方法為靜態(tài)方法

public final class Util {
   public static final Util.Companion Companion = new Util.Companion((DefaultConstructorMarker)null);
   public final void doAction1() {
      String var1 = "do action1";
      boolean var2 = false;
      System.out.println(var1);
   }
   @JvmStatic
   public static final void doAction2() {
      Companion.doAction2();
   }
   @Metadata(
      mv = {1, 1, 16},
      bv = {1, 0, 3},
      k = 1,
      d1 = {"\u0000\u0012\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0010\u0002\n\u0000\b\u0086\u0003\u0018\u00002\u00020\u0001B\u0007\b\u0002¢\u0006\u0002\u0010\u0002J\b\u0010\u0003\u001a\u00020\u0004H\u0007¨\u0006\u0005"},
      d2 = {"Ltest/Util$Companion;", "", "()V", "doAction2", "", "kotlin01"}
   )
   public static final class Companion {
      @JvmStatic
      public final void doAction2() {
         String var1 = "do action2";
         boolean var2 = false;
         System.out.println(var1);
      }
      private Companion() {
      }
      // $FF: synthetic method
      public Companion(DefaultConstructorMarker $constructor_marker) {
         this();
      }
   }
}

注意@JvmStatic注解只能加在單例類或Companion object中的方法上,如果你嘗試加在一個普通方法上,會直接提示語法錯誤。

由于doAction2()方法已經(jīng)成為真正的靜態(tài)方法,那么現(xiàn)在不管是在Kotlin中還是Java中,都可以使用Util.doAction2()的寫法來調(diào)用。

再來看頂層方法,頂層方法指的是那些沒有定義在任何類中的方法,比如我們編寫的main()方法。Kotlin編譯器會將所有的頂層方法全部編譯成靜態(tài)方法,因此只要你定義了一個頂層方法,那么它就一定是靜態(tài)方法。

想要定義一個頂層方法,首先要創(chuàng)建一個Kotlin文件。對著任意包名右擊→New→Kotlin File/Class,在彈出的對話框中輸入文件名即可。注意創(chuàng)建類型要選擇File,如圖所示

點(diǎn)擊“ok”完成創(chuàng)建,這樣剛剛的包名路徑下就會出現(xiàn)一個Helper.kt文件?,F(xiàn)在我們再這個文件中定義的任何方法都會是頂層方法,比如這里我就定義一個doSomething()方法吧,如下所示:

fun  doSomething(){
    println("do something")
}

Kotlin會將所有的頂層方法全部編譯成靜態(tài)方法,那么我們要怎么調(diào)用這個doSomething()方法呢?

如果是在Kotlin中調(diào)用的話,所有的頂層方法都可以在任何位置被直接調(diào)用,不用管包名路徑,也不用創(chuàng)建實(shí)例,直接輸入doSomething()即可。

但如果在Java代碼中調(diào)用,你會發(fā)現(xiàn)找不到doSomething()這個方法,因為Java中沒有頂層方法這個概念,所有的方法必須定義在類中。那么這個doSomething()被藏在哪里呢?我們剛才創(chuàng)建的Kotlin文件名叫做Helper.kt,于是Kotlin編譯器會自動創(chuàng)建一個叫作Helperkt的Java類,doSomething()方法就是以靜態(tài)方法的形式定義在HelperKt類里面的,因此在Java中使用Helperkt.doSomething()的寫法來調(diào)用就可以了。

到此這篇關(guān)于Kotlin標(biāo)準(zhǔn)函數(shù)與靜態(tài)方法基礎(chǔ)知識詳解的文章就介紹到這了,更多相關(guān)Kotlin標(biāo)準(zhǔn)函數(shù)與靜態(tài)方法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論