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

Kotlin學(xué)習(xí)教程之函數(shù)的默認(rèn)參數(shù)

 更新時間:2020年11月09日 11:42:11   作者:fb0122  
這篇文章主要給大家介紹了關(guān)于Kotlin學(xué)習(xí)教程之函數(shù)的默認(rèn)參數(shù),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

前言

​ 在Java中,為函數(shù)的參數(shù)添加默認(rèn)值是不被允許的,這是為了防止默認(rèn)參數(shù)與函數(shù)重載同時使用時二義性的問題,考慮下面的例子:

void func(p1: String, p2: String, p3: String = "default") {
	// do something
}

void func(String p1, String p2) {
	// do something
}

假設(shè)上面的代碼是可以編譯通過的,那么當(dāng)調(diào)用func("p1","p2") 時,編譯器會不知道到底該調(diào)用哪個方法。所以Java是不支持默認(rèn)參數(shù)的,但是依然可以通過函數(shù)重載的方式實現(xiàn)默認(rèn)參數(shù)的功能,這也是我們最普遍使用的方式:

void func(String p1, String p2, String p3) {
	// do something
}

void func(String p1, String p2) {
	func(a, b, "default");
}

通過上述函數(shù)重載的方式,也可以實現(xiàn)默認(rèn)參數(shù),但是有個問題也很明顯,就是如果要支持默認(rèn)參數(shù),我們需要寫很多的模版代碼,好像也不是那么方便。然而,Kotlin 提供了默認(rèn)參數(shù)的支持,接下來看看Kotlin中對于默認(rèn)參數(shù)的支持是怎樣的,又是怎么解決我們開始提到的那個二義性的問題的。

使用

在Kotlin中,使用默認(rèn)參數(shù)也很簡單,在函數(shù)定義中直接賦值即可:

fun func(p1: String, p2: String, p3: String = "default") {
	// do something
}

上述函數(shù)定義中,c 的默認(rèn)值就是default,可以這樣去調(diào)用 func("p1","p2")。同樣的,針對構(gòu)造函數(shù),也可以指定默認(rèn)值:

class TestDefaultParameters (
 val name: String,
 val type: String = "default"
){}

那么如果想要在Java中調(diào)用kotlin帶有默認(rèn)參數(shù)的函數(shù)怎么做呢?如果在Java中直接調(diào)用func("p1","p2")編譯器會報錯,這是需要給kotlin的方法加上Jvm重載的注解就可以了:

@JvmOverloads
fun func(p1: String, p2: String, p3: String = "default") {
	// do something
}

解析

接下來,我們看看Kotlin是如何實現(xiàn)默認(rèn)參數(shù)的,首先,寫一個例子如下:

fun main(args: Array<String>) {
 val testDefaultParameters = TestDefaultParameters("")
 testDefaultParameters.func("position1", "position2")
}

class TestDefaultParameters (
 val name: String,
 val type: String = "default"
){
 @JvmOverloads
 fun func(p1: String, p2: String, p3: String = "default") {
  // do something
 }

}

將上述的func的函數(shù)定義Decompile為Java實現(xiàn):

@JvmOverloads
public final void func(@NotNull String p1, @NotNull String p2, @NotNull String p3) {
 Intrinsics.checkParameterIsNotNull(p1, "p1");
 Intrinsics.checkParameterIsNotNull(p2, "p2");
 Intrinsics.checkParameterIsNotNull(p3, "p3");
}

// $FF: synthetic method
public static void func$default(TestDefaultParameters var0, String var1, String var2, String var3, int var4, Object var5) {
 if ((var4 & 4) != 0) {
 	var3 = "default";
	}
	var0.func(var1, var2, var3);
}

@JvmOverloads
public final void func(@NotNull String p1, @NotNull String p2) {
	func$default(this, p1, p2, (String)null, 4, (Object)null);
}
...
// 調(diào)用func函數(shù)
TestDefaultParameters.func$default(testDefaultParameters, "position1", "position2", (String)null, 4, (Object)null);

中間一些代碼我省略了,可以看到,Kotlin編譯器為我們生成了三個func的重載方法,下面我們依次來看一下分別都是什么函數(shù):

  • 首先看到的第一個函數(shù)是帶有三個參數(shù)的func,函數(shù)內(nèi)部都做了空安全的檢查,這是kotlin的特性,由于聲明函數(shù)時參數(shù)都是不為空的,所以這里需要檢查參數(shù)是否為空,會拋出異常。
  • 第二個函數(shù)我們看到名字是func$default, 并不是func的方法重載,而是一個新的方法,這就是默認(rèn)參數(shù)實現(xiàn)的關(guān)鍵方法,這里暫且按下不表,后面詳細(xì)講解。
  • 第三個函數(shù)依然是func方法的重載,可以看到這個方法只有兩個參數(shù),并且內(nèi)部調(diào)用了第二個方法。其實這個方法是給Java調(diào)用的,由于我們將func函數(shù)聲明為@JvmOverloads,所以當(dāng)Java在不傳遞默認(rèn)參數(shù)調(diào)用func的時候,實際上調(diào)用的是這個方法。如果將@JvmOverloads去掉的話,是沒有這個方法的。

在了解了三個方法的作用之后,主要來看一下第二個方法:

// $FF: synthetic method
public static void func$default(TestDefaultParameters var0, String var1, String var2, String var3, int var4, Object var5) {
 if ((var4 & 4) != 0) {
 	var3 = "default";
	}
	var0.func(var1, var2, var3);
}

可以看到這個方法有6個參數(shù),var0為Class對象,var1 ~var3 分別對應(yīng)func函數(shù)的三個參數(shù),然后有一個int類型的var4和一個Object類型的 var5。var5這個大多數(shù)情況下都為null,默認(rèn)參數(shù)實現(xiàn)的秘密主要是在這個var 4上, 來看看當(dāng)調(diào)用函數(shù)使用默認(rèn)參數(shù)時,是怎么調(diào)用的:

// kotlin
func("position1", "position2")
 
// Decompile
func$default(testDefaultParameters, "position1", "position2", (String)null, 4, (Object)null)

看到var4的值為4。是由于原函數(shù)是第三個參數(shù)為默認(rèn)參數(shù),即 position = 2位置的參數(shù),所以 var4 = 222^222=4
在看之前func$default 的方法實現(xiàn):

if ((var4 & 4) != 0) {
 var3 = "default";
}

當(dāng)var4 & 4 != 0的時候,var3的值就等于默認(rèn)參數(shù)??梢园l(fā)現(xiàn),func$default函數(shù)的int類型的參數(shù)就是表示第幾個參數(shù)的值是默認(rèn)參數(shù)的。下面看一個稍微復(fù)雜的例子:

fun func(p1: String = "position1", p2: String = "position2", p3: String = "position3") {
   // do something
}

// 調(diào)用
testDefaultParameters.func(p2 = "position2")

這次三個參數(shù)都有默認(rèn)值,且調(diào)用時用具名參數(shù)指定p2的值為"position2"。下面看看Decompile后的代碼:

// $FF: synthetic method
public static void func$default(TestDefaultParameters var0, String var1, String var2, String var3, int var4, Object var5) {
if ((var4 & 1) != 0) {
 var1 = "position1";
}

if ((var4 & 2) != 0) {
 var2 = "position2";
}

if ((var4 & 4) != 0) {
 var3 = "position3";
}

 var0.func(var1, var2, var3);
}

// 調(diào)用
func$default(testDefaultParameters, (String)null, "position2", (String)null, 5, (Object)null)

可以看到,這次方法體內(nèi)有三個判斷,因為有三個參數(shù)都是有默認(rèn)值的,傳遞的參數(shù)為5,是由于函數(shù)調(diào)用時,index=0 和 index=2的參數(shù)為默認(rèn)參數(shù),所以 var4 = 20+222^0 + 2^220+22 = 5。

這里大概解釋一下為什么要這么設(shè)計的原因:
當(dāng)寫有多個條件,例如權(quán)限判斷,index判斷等邏輯的時候非常適合位運算。例如在上面的例子中,參數(shù)的index可以表示為:2的index冪的二進(jìn)制數(shù),例如 index = 0 即 202^020 , 用二進(jìn)制表示為:0001,index = 1 即 212^121 ,表示為:0010(可以看作是二進(jìn)制數(shù)中1的位置,即表示index)。
那么如果多個位置比如index=0與index=2呢?既可以表示為:0101。就是 20+22=52^0 + 2^2 = 520+22=5 。與目標(biāo)所在的index進(jìn)行按位與運算的時候,如果不等于0就表示該index符合條件。否則不符合。

回過頭來看上述func$default函數(shù)體就清晰了,就是通過位置判斷,當(dāng)不是使用默認(rèn)值的位置時,就不使用默認(rèn)值。

上述例子中,我們看到含有默認(rèn)值的參數(shù)的函數(shù)在Decompile之后,有一個始終為null的Object參數(shù),而且也沒有被使用到。那么這個參數(shù)有什么用呢?這個參數(shù)會在嘗試重寫有默認(rèn)參數(shù)的函數(shù)時用到。例如下面的例子:

open class TestDefaultParameters {
  open fun func(p1: String = "position1", p2: String = "position2", p3: String = "position3") {
    // do something
  }
}

class TestDefaultChild : TestDefaultParameters() {
  override fun func(p1: String, p2: String, p3: String) {
    // do something
  }
}

將上述代碼編譯一下:

// $FF: synthetic method
public static void func$default(TestDefaultParameters var0, String var1, String var2, String var3, int var4, Object var5) {
  if (var5 != null) {
    throw new UnsupportedOperationException("Super calls with default arguments not supported in this target, function: func");
  } else {
    if ((var4 & 1) != 0) {
     var1 = "position1";
    }

    if ((var4 & 2) != 0) {
     var2 = "position2";
    }

    if ((var4 & 4) != 0) {
     var3 = "position3";
    }

    var0.func(var1, var2, var3);
}
}

可以看到,當(dāng)調(diào)用超類使用默認(rèn)參數(shù)在當(dāng)前版本是不允許的(以后可能允許)。這就是Object參數(shù)的用處。

總結(jié)

以上就是對kotlin的默認(rèn)參數(shù)實現(xiàn)的一些總結(jié)。

到此這篇關(guān)于Kotlin學(xué)習(xí)教程之函數(shù)的默認(rèn)參數(shù)的文章就介紹到這了,更多相關(guān)Kotlin函數(shù)的默認(rèn)參數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Cocos2d-x 3.0中集成社交分享ShareSDK的詳細(xì)步驟和常見問題解決

    Cocos2d-x 3.0中集成社交分享ShareSDK的詳細(xì)步驟和常見問題解決

    這篇文章主要介紹了Cocos2d-x 3.0中集成社交分享ShareSDK的詳細(xì)步驟和常見問題的解決方法以及需要注意的問題,需要的朋友可以參考下
    2014-04-04
  • Android編程實現(xiàn)異步消息處理機(jī)制的幾種方法總結(jié)

    Android編程實現(xiàn)異步消息處理機(jī)制的幾種方法總結(jié)

    這篇文章主要介紹了Android編程實現(xiàn)異步消息處理機(jī)制的幾種方法,結(jié)合實例形式詳細(xì)總結(jié)分析了Android異步消息處理機(jī)制的原理、相關(guān)實現(xiàn)技巧與操作注意事項,需要的朋友可以參考下
    2018-08-08
  • Android實現(xiàn)本地上傳圖片并設(shè)置為圓形頭像

    Android實現(xiàn)本地上傳圖片并設(shè)置為圓形頭像

    我們在做項目的時候會用到圓形的圖片,比如用戶頭像,類似QQ。用戶在用QQ更換頭像的時候,上傳的圖片都是矩形的,但顯示的時候確是圓形的。那么這是如何實現(xiàn)的呢,下面我們就來探討下吧。
    2015-05-05
  • 使用DrawerLayout組件實現(xiàn)側(cè)滑抽屜的功能

    使用DrawerLayout組件實現(xiàn)側(cè)滑抽屜的功能

    DrawerLayout組件同樣是V4包中的組件,也是直接繼承于ViewGroup類,所以說是一個容器類,下面通過本文給大家介紹使用DrawerLayout組件實現(xiàn)側(cè)滑抽屜的功能,感興趣的朋友一起看下吧
    2016-08-08
  • RxJava2.x實現(xiàn)定時器的實例代碼

    RxJava2.x實現(xiàn)定時器的實例代碼

    本篇文章主要介紹了RxJava2.x實現(xiàn)定時器,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-06-06
  • 詳解Android?Flutter如何使用相機(jī)實現(xiàn)拍攝照片

    詳解Android?Flutter如何使用相機(jī)實現(xiàn)拍攝照片

    在app中使用相機(jī)肯定是再平常不過的一項事情了,相機(jī)肯定涉及到了底層原生代碼的調(diào)用,那么在flutter中如何快速簡單的使用上相機(jī)的功能呢?一起來看看吧
    2023-04-04
  • Android實現(xiàn)手機(jī)監(jiān)控攝像頭

    Android實現(xiàn)手機(jī)監(jiān)控攝像頭

    這篇文章主要為大家詳細(xì)介紹了Android實現(xiàn)手機(jī)監(jiān)控攝像頭,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • Android自定義控件仿QQ抽屜效果

    Android自定義控件仿QQ抽屜效果

    這篇文章主要為大家詳細(xì)介紹了Android自定義控件仿QQ抽屜效果的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-03-03
  • Android NDK開發(fā)入門

    Android NDK開發(fā)入門

    本文主要對NDK產(chǎn)生的背景、使用NDK原因、NDK簡介、NDK開發(fā)環(huán)境的搭建、如何運行NDK提供的事例demo等進(jìn)行了詳細(xì)的介紹。具有很好的參考價值,需要的朋友一起來看下吧
    2016-12-12
  • Android側(cè)滑菜單之DrawerLayout用法詳解

    Android側(cè)滑菜單之DrawerLayout用法詳解

    今天小編就為大家分享一篇關(guān)于Android側(cè)滑菜單之DrawerLayout用法詳解,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-03-03

最新評論