在上一篇文章中介紹了Kotlin的一些基本語(yǔ)法,包括變量、常量的定義、控制循環(huán)語(yǔ)句、函數(shù)的定義及使用、類的定義、方法和屬性、繼承、數(shù)據(jù)類、枚舉類、異常處理、類型檢查和轉(zhuǎn)換等部分的內(nèi)容。這這篇文章中記錄一下接口、泛型以及擴(kuò)展的部分內(nèi)容。
接上篇繼續(xù)
8、接口:
在java語(yǔ)言中也有接口的定義,和kotlin中相比相差不大。那什么是接口呢?
接口就是對(duì)方法或者屬性的實(shí)現(xiàn)標(biāo)準(zhǔn)。這樣說(shuō)可能有點(diǎn)抽象。舉個(gè)例子:每一個(gè)自然人呢都有一個(gè)名字,然后現(xiàn)在有一個(gè)歪果仁想要加入中國(guó)的國(guó)籍,想要以后在中國(guó)發(fā)展。那咱們定義一個(gè)人(Person)的類,然后再定義一個(gè)歪果仁(ForigChinese)的類去繼承人(Person)的類。
這時(shí)候這個(gè)歪果仁要加入中國(guó)的國(guó)籍,那怎么辦呢,我們不能在Person類中添加加入中國(guó)國(guó)籍的方法。所以我們?nèi)懸粋€(gè)接口,定義一個(gè)加入中國(guó)國(guó)籍的方法,讓想要加入中國(guó)國(guó)籍的歪果仁去實(shí)現(xiàn)這個(gè)方法。這樣,這個(gè)歪果仁的實(shí)例就可以去調(diào)用加入中國(guó)國(guó)籍的方法了。
具體的咱們來(lái)看下邊的代碼:
首先定義一個(gè)Person類,因?yàn)檫@個(gè)類需要被其他的類繼承,所以使用open關(guān)鍵字來(lái)修飾
open class Person {
var name = ""
}
然后去定義一個(gè)可以生存的接口:
interface Livable {
//接口中的屬性和方法不能初始化
var hasSkill: Boolean//接口中的屬性
fun addChina() //接口中的方法
//接口中的方法可以有默認(rèn)實(shí)現(xiàn),通常指該方法是固定不變的
fun SpeakChinese() {
LogUtils.Loge("接口中的默認(rèn)方法:我可以說(shuō)中文")
}
}
然后定義一個(gè)可以在中國(guó)生存的接口:
interface ChinaLivable {
//接口中的屬性不可初始化
val hasJobOffer: Boolean
//接口中可以有g(shù)et方法,通常用于增加一個(gè)常量屬性
val visaCatagory: String
get() = "工作offer"
//接口中的屬性
var city: String
}
然后去定義一個(gè)歪果仁的類繼承Person類,并且實(shí)現(xiàn)生存接口和在中國(guó)生存的接口:
class ForigChinese : Person(), Livable, ChinaLivable {
override var hasJobOffer: Boolean = true
override var city: String = "北京"
override var hasSkill: Boolean = true
override fun addChina() {
LogUtils.Loge("我叫${name}我要加入中國(guó)國(guó)籍")
}
}
這時(shí)候,這個(gè)歪果仁就有了生存的能力,并且有了在總過(guò)生存的能力。所以他就能加入中國(guó)國(guó)籍了。
var mForigChinese = ForigChinese()
mForigChinese.name = "小米"
mForigChinese.city = "北京"
mForigChinese.hasJobOffer = true
mForigChinese.hasSkill = true
mForigChinese.addChina()
mForigChinese.SpeakChinese()
LogUtils.Loge("接口名稱:" + mForigChinese.name)
LogUtils.Loge("接口城市:" + mForigChinese.city)
LogUtils.Loge("接口是否有工作:" + mForigChinese.hasJobOffer)
LogUtils.Loge("接口是否有生存技能:" + mForigChinese.hasSkill)
然后看一下Log:
11-16 15:49:22.968 4994-4994/com.example.lql.kotlindemo E/###: 我叫小米我要加入中國(guó)國(guó)籍###
11-16 15:49:22.968 4994-4994/com.example.lql.kotlindemo E/###: 接口中的默認(rèn)方法:我可以說(shuō)中文###
11-16 15:49:22.968 4994-4994/com.example.lql.kotlindemo E/###: 接口名稱:小米###
11-16 15:49:22.968 4994-4994/com.example.lql.kotlindemo E/###: 接口城市:北京###
11-16 15:49:22.968 4994-4994/com.example.lql.kotlindemo E/###: 接口是否有工作:true###
11-16 15:49:22.968 4994-4994/com.example.lql.kotlindemo E/###: 接口是否有生存技能:true###
我們發(fā)現(xiàn)我們給歪果仁(ForigChinese )類添加了兩個(gè)能力,一個(gè)是生存的能力,一個(gè)是在中國(guó)生存的能力,但是ForigChinese類本身看起來(lái)并沒(méi)有復(fù)雜。所以,接口可以給 類附加能力,并且讓類看起來(lái)很簡(jiǎn)潔。
還有一點(diǎn),這個(gè)能力并沒(méi)有在父類中去實(shí)現(xiàn),所以通過(guò)接口的方法來(lái)實(shí)現(xiàn)某些功能,是可以選擇的,如果我不想要在中國(guó)生存的能力,就可以不實(shí)現(xiàn)這個(gè)接口就好了。使用起來(lái)很方便。
9、泛型:
泛型就是讓一個(gè)函數(shù)或者類能更加通用,首先咱們看一下系統(tǒng)給提供的一下泛型的方法。
//定義一個(gè)Int類型的數(shù)組
var intList = arrayOf(1, 2, 3, 4, 5, 6, 7, 10)
//定義一個(gè)String類型的數(shù)組
var stringList = arrayOf("1","2","3","4","5","6","7","9")
我們發(fā)現(xiàn)arrayOf方法,我們既可以傳Int類型的參數(shù)進(jìn)去,也可以傳String類型的參數(shù)進(jìn)去。這就是泛型方法的體現(xiàn)。
在我們定義方法或者類的時(shí)候,有時(shí)候也要考慮這個(gè)因素進(jìn)去,我們寫了一個(gè)工具類,能不能傳遞不同類型的傳輸進(jìn)去呢?這可以讓方法在更多的情境下使用。
9.1基本泛型
然后我們來(lái)看一下泛型在Kotlin中的寫法:
//定義一個(gè)泛型函數(shù): <T> T表示一個(gè)占位符
fun <T> showText(para: T) {
LogUtils.Loge("泛型入?yún)ⅲ? + para.toString())
}
然后調(diào)用這個(gè)方法:
showText(3)
showText("123")
Log:
11-16 16:02:29.258 4994-4994/com.example.lql.kotlindemo E/###: 泛型入?yún)ⅲ?###
11-16 16:02:29.258 4994-4994/com.example.lql.kotlindemo E/###: 泛型入?yún)ⅲ?23###
我們可以看到對(duì)與一個(gè)方法showText()傳遞了兩種不同類型的參數(shù)進(jìn)去。
9.2約束泛型:
現(xiàn)在我們有一個(gè)數(shù)組
arrayOf(1, 2, 3, 4, 5, 6, 7, 10, 11)
我們相對(duì)這個(gè)數(shù)組求和,這個(gè)時(shí)候我們參數(shù)都是Int類型的,我們可以直接調(diào)用.sum()方法去求和。
然后咱們把數(shù)組改一下
arrayOf(1, 2, 3, 4, 5, 6, 7, 10, 11.11)
這樣,里邊多了一個(gè)double類型的元素。這時(shí)候就沒(méi)辦法調(diào)用.sum()方法了。然后我們使用約束泛型去實(shí)現(xiàn)一個(gè)求和方法:
//下邊就是泛型約束:<泛型占位符: 類型> 把泛型約束在Number類型中
fun <T : Number> sum2(vararg number: T): Double {
return number.sumByDouble { it.toDouble() }
}
通過(guò)上邊的注釋,大家應(yīng)該能看懂這個(gè)約束泛型的意思。就不再解釋了。
9.3多重約束泛型:
寫法就是把多個(gè)約束用where修飾,中間使用“ , ”隔開(kāi),寫在函數(shù)體之前。
例子:把數(shù)組中大于某個(gè)元素的部分都取出來(lái)并升序排列
//Comparable 可比較的,大于、小于、等于
fun <T> biggerPart(list: Array<T>, threhold: T): List<T> where T : Number, T : Comparable<T> {
return list.filter { it >= threhold }.sorted()
}
來(lái)看一下試用方法:
//多重約束
val biggerPart = biggerPart(arrayOf(99, 1, 2, -2, 88, 1024, 888), 3)
for (i in biggerPart) {
LogUtils.Loge("多重約束:${i}")
}
Log:
11-16 16:02:29.258 4994-4994/com.example.lql.kotlindemo E/###: 泛型約束:38.11###
11-16 16:02:29.258 4994-4994/com.example.lql.kotlindemo E/###: 多重約束:88###
11-16 16:02:29.258 4994-4994/com.example.lql.kotlindemo E/###: 多重約束:99###
11-16 16:02:29.258 4994-4994/com.example.lql.kotlindemo E/###: 多重約束:888###
11-16 16:02:29.258 4994-4994/com.example.lql.kotlindemo E/###: 多重約束:1024###
10、擴(kuò)展:
所謂擴(kuò)展,就是對(duì)已經(jīng)有的類,但是不能修改源碼的這種去增加一些方法。添加方法的時(shí)候要注意盡量不要和類中已經(jīng)有的方法重名,如果非要重名,那類型也不要相同。簡(jiǎn)單來(lái)說(shuō)就是別一毛一樣。舉個(gè)例子:咱們要Toast一下,但是每次寫吐司都寫的比較長(zhǎng),怎么辦呢?咱們就用這個(gè)類的擴(kuò)展,對(duì)Context類寫一個(gè)Toast擴(kuò)展:
fun Context.ToastKotlin(message: String) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
同樣使用也很簡(jiǎn)單(這是一個(gè)recyclerview的點(diǎn)擊事件):
mTestAdapter!!.setOnItemClickListener(OnItemClickListener { view, position ->
this.ToastKotlin("adapter的點(diǎn)擊事件${position}")
})
尷尬的事情出現(xiàn)了,在Kotlin中已經(jīng)幫咱們寫了這個(gè)擴(kuò)展方法了,相信大家調(diào)用的時(shí)候會(huì)發(fā)現(xiàn)這個(gè)問(wèn)題,但是大家懂了這個(gè)意思就好了。然后咱們看一下其他的例子具體的寫法:
//擴(kuò)展函數(shù):fun 接受者類型.新擴(kuò)展函數(shù)名(參數(shù)類別){//函數(shù)實(shí)現(xiàn)}
//1、函數(shù)擴(kuò)展
fun Int.square(): Int {
return this * this
}
//2、泛型函數(shù)擴(kuò)展:求數(shù)字型數(shù)組中的最大元素
fun <T> Array<T>.biggest(): T
where T : Number,
T : Comparable<T> {
var biggest = this[0]
for (t in this) {
if (t > biggest) {
biggest = t
}
}
return biggest
}
// 3、屬性的擴(kuò)展(普通屬性)
val Int.next: Int
get() = this + 1
//4、泛型屬性 數(shù)字類型的半徑 的面積
val <T : Number> T.area: Double
get() = 3.1425926 * this.toDouble() * this.toDouble()
使用:
LogUtils.Loge("函數(shù)擴(kuò)展:" + 3.square())
val a = arrayOf(1, 2, 3, 4, 5, 8)
LogUtils.Loge("求最大" + a.max())
val biggest = a.biggest()
LogUtils.Loge("自己寫一個(gè)求最大:" + biggest)
LogUtils.Loge("屬性擴(kuò)展:" + 3.next)
LogUtils.Loge("屬性泛型擴(kuò)展:" + 3.area)
LogUtils.Loge("屬性泛型擴(kuò)展:" + 'B'.toByte().area)
Log:
11-16 16:16:59.348 4994-4994/com.example.lql.kotlindemo E/###: 函數(shù)擴(kuò)展:9###
11-16 16:16:59.348 4994-4994/com.example.lql.kotlindemo E/###: 求最大8###
11-16 16:16:59.348 4994-4994/com.example.lql.kotlindemo E/###: 自己寫一個(gè)求最大:8###
11-16 16:16:59.348 4994-4994/com.example.lql.kotlindemo E/###: 屬性擴(kuò)展:4###
11-16 16:16:59.348 4994-4994/com.example.lql.kotlindemo E/###: 屬性泛型擴(kuò)展:28.283333399999997###
11-16 16:16:59.348 4994-4994/com.example.lql.kotlindemo E/###: 屬性泛型擴(kuò)展:13689.1333656###
這一部分,大家一看就知道具體的意思了,就不解釋了。
好啦,通過(guò)兩篇文章記錄了一下Kotlin中變量的定義、元組的使用、循環(huán)控制流的使用、類的相關(guān)使用、異常處理、接口、泛型和擴(kuò)展部分的內(nèi)容。最開(kāi)始學(xué)習(xí)Kotli就先聊這么多。我需要繼續(xù)學(xué)習(xí)了。還是上一篇中的那句話,剛開(kāi)始學(xué)習(xí)使用Kotlin,可能對(duì)概念以及用法的認(rèn)識(shí)有偏差,如有錯(cuò)誤,希望大家給予指正!