上一節(jié)我們學(xué)習(xí)了Kotlin的一些基礎(chǔ)語(yǔ)法包括和java語(yǔ)言的一些區(qū)別,雖然說(shuō)java和kotlin是無(wú)縫對(duì)接,但是他們彼此之間相互調(diào)用還有一些需要注意的地方,
一、java與Kotlin互相調(diào)用
1、kotlin調(diào)用java時(shí),需要做非空的判斷處理,這樣避免出現(xiàn)空指針異常
2、kotlin調(diào)用java的接口,可以使用(object : javaCallback )進(jìn)行實(shí)例化后實(shí)現(xiàn)接口的方法
可以直接使用({這里顯示接口方法的函數(shù)體}) 直接創(chuàng)建接口的的實(shí)例,并實(shí)現(xiàn)接口3、java調(diào)用kotlin的方法,可以通過(guò)文件的名.方法名來(lái)進(jìn)行調(diào)用,但是如果不想讓java調(diào)用,可以使用雙單引號(hào)將方法名字包含起來(lái)就無(wú)法調(diào)用了
fun 'show'(){ //此方法無(wú)法被java調(diào)用 }4、kotlin中的擴(kuò)展函數(shù)(就是可以在任何地方為一個(gè)類擴(kuò)展一個(gè)函數(shù))
class student{ } //此時(shí)為student添加了一個(gè)擴(kuò)展函數(shù) fun student.add(var number:Int,var number2:Int){ } fun main():Int{ student.add(1,2); }5、kotlin泛型
1)java中泛型的通配符是? 而Kotlin泛型的通配符是 *
2)kotlin 中的out 相當(dāng)于java是 extends 只讀 輸出
in 相當(dāng)于java是 super 只寫 輸入open class fuclass { var name1 = "fuclass" } class ziclass : fuclass() { var name = "ziclass" } fun main() { /** * TODO in out 的讀寫模式 */ var list: MutableList<out fuclass> = ArrayList<ziclass>() var temp = ziclass() // list.add(temp)//不能修改 報(bào)錯(cuò) var item1 = list.get(0)//獲取 var list2: MutableList<in ziclass> = ArrayList<fuclass>() // list2.add(fuclass()) var item = list2[0] println("name=${(item as ziclass).name},name1=${item.name1}") }3) in out 在類的聲明泛型時(shí)作用:可以控制整個(gè)類泛型讀寫模式, 而java中不能在泛型聲明的時(shí)候限定泛型的讀寫模式
n 說(shuō)明該類的泛型只能寫 相當(dāng)于輸入,就是只寫的 out 說(shuō)明該類的泛型只能獲取 相當(dāng)于輸出,就是只讀的 不使用in out 說(shuō)明該類的泛型既可以輸入,也可以輸出//在聲明泛型時(shí)候的泛型讀寫模式的限定 class Student<in T> { //可寫 fun setData(data: T) { } //不可讀,報(bào)錯(cuò) fun getData(): T?{ return null } } class Teacher<out T> { //不可寫,報(bào)錯(cuò) // fun setData(data: T) { // } //可讀 fun getData(): T? { return null } }
二、高階函數(shù)
概念:將函數(shù)作為參數(shù)傳遞給主函數(shù),該主函數(shù)稱為高階函數(shù)。
高階函數(shù)在kotlin中隨處可見(jiàn),想要深刻理解高階函數(shù),需要先來(lái)學(xué)習(xí)一下lambda表達(dá)式,這樣就讓你學(xué)起高階函數(shù)了達(dá)到事半功倍的效果。
2.1)lambda表達(dá)式
1、:() 括號(hào)中是參數(shù)
2、={} 括號(hào)中是函數(shù)體
3、var 變成val 后就不可以覆蓋了
4、只有一個(gè)參數(shù)時(shí)可以不寫(默認(rèn)是it),多個(gè)參數(shù)則需要寫清楚
//() 參數(shù)為空,返回值:Unit 函數(shù)名method , 該函數(shù)不能調(diào)用,因?yàn)闆](méi)有函數(shù)體
var method:()->Unit
//有函數(shù)體,可以調(diào)用
var method1:(Int ,Int)->Int={number1+number2=number1+number2}
method1(9,9)
var method3={number1:Int,number2:Int-> number1+number2}
//只有一個(gè)參數(shù)
var m10 : (Int) -> Unit = {
when(it) {
1 -> println("你是一")
in 20..30 -> println("你是 二十 到 三十")
else -> println("其他的數(shù)字")
}
}
m10(29)
//無(wú)參數(shù)
var m12 = { println("我就是m12函數(shù),我就是我") }
m12()
// 覆蓋操作
var m14 = {number: Int -> println("我就是m14 我的值: $number")}
m14 = {println("覆蓋 我的值: $it")}
m14(99)
2.2)高階:
1、高階函數(shù)的最后一個(gè)參數(shù)是一個(gè)函數(shù)時(shí),在實(shí)現(xiàn)函數(shù)體時(shí) 可以在函數(shù)參數(shù)括號(hào)外使用{}來(lái)實(shí)現(xiàn)函數(shù)參數(shù)的函數(shù)體
2、使用typealias 來(lái)給高階函數(shù)起一個(gè)別名 typealias LOGIN= (String, String) -> Unit 他就像一個(gè)數(shù)據(jù)類型一樣的使用
3、當(dāng)函數(shù)參數(shù)只有一個(gè)參數(shù)時(shí),可以直接使用{}進(jìn)行閉包,默認(rèn)將一個(gè)參數(shù)命名為it,
有多個(gè)參數(shù)時(shí),無(wú)法默認(rèn) 則需要指明參數(shù)名,并用->指向函數(shù)體4、 如果函數(shù)參數(shù)已經(jīng)有了實(shí)現(xiàn)體,那么可以通過(guò):: 來(lái)直接調(diào)用;
:: 內(nèi)部原理:就是將show_run函數(shù)的對(duì)象賦值給show_14的參數(shù),那么說(shuō)明show_run 是可以賦值給一個(gè)變量的
下面是typealias 的使用:
//類似于typedef
typealias LOGIN = (String, String) -> Unit
fun main(){
fun loginService(username: String, password: String, login: (String, String) -> Unit) {
login(username, password)
}
//高級(jí)別名的使用
fun loginService2(username: String, password: String, login: LOGIN) {
login(username, password)
}
//真正使用
fun loginEngine(username: String, password: String): Unit {
loginService(username, password) { username, pwd ->
//此處就是高階函數(shù)的函數(shù)體
println("username=${username},pwd=${password}")
}
}
loginEngine("leon", "123456")
}
下面是一個(gè)或多個(gè)參數(shù)的使用:
fun main(){
// 多個(gè)參數(shù)的函數(shù)參數(shù)
fun show(mm: (String) -> Unit) {
mm("一個(gè)參數(shù)")
}
show {
println("一個(gè)參數(shù)的函數(shù)參數(shù):$it")
}
fun show1(mm: (String, Int) -> Unit) {
mm("多個(gè)個(gè)參數(shù)", 1)
}
//下面是調(diào)用
show1 { param1, param2 ->
println("多個(gè)參數(shù)的函數(shù)參數(shù):param1=$param1,param2=$param2")
}
}
下面是::來(lái)調(diào)用
fun main(){
// :: 來(lái)調(diào)用高階的函數(shù)參數(shù)
fun show_14(number: Int, mm: (Int) -> String): String {
return mm(number)
}
fun show_run(number: Int) = "通過(guò):: 來(lái)調(diào)用函數(shù)參數(shù)的實(shí)現(xiàn)函數(shù)_$number"
//
val showRunObj = ::show_run
println(show_14(50, showRunObj))
println(show_14(100, ::show_run))
}
2.3) 高階里面的手寫標(biāo)準(zhǔn)
1、kotlin中的泛型除了數(shù)據(jù)類型,還包含了方法,方法也算一個(gè)類型,即萬(wàn)能類型
2、T 是泛型,R是返回類型的泛型
3、T.MyRun相當(dāng)于給泛型T增加了一個(gè)MyRun的擴(kuò)展函數(shù), mm: T.() -> R 代表給T增加一個(gè)匿名的擴(kuò)展函數(shù)
4、類似于RxJava中的鏈?zhǔn)秸{(diào)用
fun main(){
fun <T, R> T.MyRun(mm: () -> R): R {
return mm()
}
//給T增加一個(gè)匿名函數(shù) T.()
fun <T, R> myWith(input: T, mm: T.() -> R): R {
return input.mm()
}
var age = 0
age.MyRun {
"headworld"
}
var name = "Leon"
myWith(name) {
length//此時(shí)可以直接獲取name的長(zhǎng)度
}
}
2.4 高階里面的標(biāo)準(zhǔn)特色:let、apply 、also、run、with、takeIf、takeUnless、repeat
kotlin給我們提供了很多類似的標(biāo)準(zhǔn),可以參考Standard.kt里面的自己去學(xué)習(xí),
let : 其實(shí)就是將調(diào)用類型的對(duì)象自己作為參數(shù)傳遞給block的函數(shù)體
apply: 其實(shí)就是在執(zhí)行完block函數(shù)后,將apply的調(diào)用者返回,類似于建造者模式的鏈?zhǔn)秸{(diào)用
also:將當(dāng)前調(diào)用者作為參數(shù)傳遞給block函數(shù),并將調(diào)用者作為返回值返回,便于鏈?zhǔn)秸{(diào)用
run: 將調(diào)用者作為參數(shù)傳遞給block函數(shù),并將block執(zhí)行的結(jié)果返回
5)with:使用指定的receiver作為接受者調(diào)用block函數(shù)后,將block函數(shù)執(zhí)行的結(jié)果返回
6)takeIf:當(dāng)調(diào)用者滿足predicate的條件時(shí)返回調(diào)用者,不滿足時(shí)返回null
takeUnless: 和takeIf正好相反7)repeat: 其實(shí)就是系統(tǒng)提供出來(lái)的一個(gè)輪詢器,方便我們遍歷數(shù)組
var Leon = "Leon"
Leon.let {
println("let 參數(shù)it的值是${it}")
}
var temp = Leon.apply {
println("apply 回傳的this的值是$this")
}
println("apply 執(zhí)行后的結(jié)果$temp")
repeat(Leon.length) {
println("repeat輪詢:it=${it},leon的當(dāng)前位置的字符是:${Leon[it]}")
}
//輸出的結(jié)果如下:
//let 參數(shù)it的值是Leon
//apply 回傳的this的值是Leon
//apply 執(zhí)行后的結(jié)果Leon
//repeat輪詢:it=0,leon的當(dāng)前位置的字符是:L
//repeat輪詢:it=1,leon的當(dāng)前位置的字符是:e
//repeat輪詢:it=2,leon的當(dāng)前位置的字符是:o
//repeat輪詢:it=3,leon的當(dāng)前位置的字符是:n
雖然kotlin給我們提供了很多標(biāo)準(zhǔn),其實(shí)我們還是可以自己定義我們所需要的的標(biāo)準(zhǔn)的,下面來(lái)模仿一下系統(tǒng)的repeat 做一個(gè)自定義
說(shuō)明:
1)我們?cè)谑褂孟聵?biāo)的時(shí)候,下標(biāo)從0 開始,所有這里在執(zhí)行輪詢的時(shí)候,需要使用區(qū)間,但是必須until 去掉尾部,否則會(huì)多執(zhí)行一次
2)step 后面的步長(zhǎng),必須要明確說(shuō)明,不能作為參數(shù)來(lái)進(jìn)行賦值
3)真正的操作是在action這個(gè)函數(shù)參數(shù)的函數(shù)體內(nèi)完成
fun main(){
fun doWhile(count: Int, action: (Int) -> Unit) {
for (index in 0 until count step 1) {
action(index)
}
}
doWhile(10) {
println("自定義輪詢器的下標(biāo):$it")
}
}
//輸出結(jié)果如下:
自定義輪詢器的下標(biāo):0
自定義輪詢器的下標(biāo):1
自定義輪詢器的下標(biāo):2
自定義輪詢器的下標(biāo):3
自定義輪詢器的下標(biāo):4
自定義輪詢器的下標(biāo):5
自定義輪詢器的下標(biāo):6
自定義輪詢器的下標(biāo):7
自定義輪詢器的下標(biāo):8
自定義輪詢器的下標(biāo):9
2.5)自定義線程的封裝
1)我們分封裝的線程,這樣后續(xù)我們可以直接值關(guān)心耗時(shí)操作即可,
2) openThread 可以作為一個(gè)模板來(lái)使用
fun openThread(start: Boolean, RunTask: () -> Unit): Thread? {
val thread = object : Thread() {
override fun run() {
super.run()
RunTask()
}
}
return if (start) {
thread.start()
thread
} else {
null
}
}
fun main(){
//對(duì)比系統(tǒng)的thread代碼,大體類似
openThread(true) {
println("我是在子線程中執(zhí)行的耗時(shí)操作:輸出字符串")
}
}
今天我們主要學(xué)習(xí)了一下kotlin和java互相調(diào)用時(shí)一些需要注意的點(diǎn),著重學(xué)習(xí)了kotlin中的高階和自定義標(biāo)準(zhǔn)模板,希望對(duì)各位看官有所幫助。