系列文章全部為本人的學(xué)習(xí)筆記禁悠,若有任何不妥之處弃揽,隨時歡迎拍磚指正鼓择。如果你覺得我的文章對你有用三幻,歡迎關(guān)注我,我們一起學(xué)習(xí)進(jìn)步呐能!
Kotlin學(xué)習(xí)筆記(1)- 環(huán)境配置
Kotlin學(xué)習(xí)筆記(2)- 空安全
Kotlin學(xué)習(xí)筆記(3)- 語法
Kotlin學(xué)習(xí)筆記(4)- 流程控制
Kotlin學(xué)習(xí)筆記(5)- 類
Kotlin學(xué)習(xí)筆記(6)- 屬性
Kotlin學(xué)習(xí)筆記(7)- 接口
Kotlin學(xué)習(xí)筆記(8)- 擴展
Kotlin學(xué)習(xí)筆記(8)- 擴展(續(xù))
Kotlin學(xué)習(xí)筆記(9)- 數(shù)據(jù)類
Kotlin學(xué)習(xí)筆記(10)- 泛型
Kotlin學(xué)習(xí)筆記(11)- 內(nèi)部類和嵌套類
Kotlin學(xué)習(xí)筆記(12)- 委托
Kotlin學(xué)習(xí)筆記(13)- 函數(shù)式編程
Kotlin學(xué)習(xí)筆記(14)- lambda
今天要開始學(xué)習(xí)擴展(Extension)了念搬,擴展是kotlin中非常重要的一個特性,它能讓我們對一些已有的類進(jìn)行功能增加摆出、簡化朗徊,使他們更好的應(yīng)對我們的需求。這么說可能有點枯燥偎漫,我們先來看一個小栗子爷恳。
// 對Context的擴展,增加了toast方法象踊。為了更好的看到效果舌仍,我還加了一段log日志
fun Context.toast(msg : String){
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
Log.d("text", "Toast msg : $msg")
}
// Activity類,由于所有Activity都是Context的子類通危,所以可以直接使用擴展的toast方法
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
......
toast("hello, Extension")
}
}
// 輸出
Toast msg : hello, Extension
怎么樣,有沒有一點小激動灌曙,反正我是有的菊碟。按照通常的做法,我們會寫一個ToastUtils
工具類在刺,或者在BaseActivity
中實現(xiàn)toast
方法逆害,但是現(xiàn)在這些統(tǒng)統(tǒng)不需要了头镊,直接給Context
增加擴展,這樣不論是Activity
或者Service
都可以直接調(diào)用魄幕,更簡潔相艇、更優(yōu)雅。接下來是我的學(xué)習(xí)進(jìn)程纯陨,希望也能對你有所幫助坛芽。
一、擴展方法(Extension Function)
擴展方法翼抠,顧名思義咙轩,就是對類的方法進(jìn)行擴展,寫法和定義方法類似阴颖,但是要聲明目標(biāo)類活喊,也就是對哪個類進(jìn)行擴展,kotlin中稱之為Top Level
量愧。就比如上面的栗子钾菊。
fun Context.toast(msg : String){
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
Log.d("text", "Toast msg : $msg")
}
其中,Context
就是目標(biāo)類(Top Level)偎肃,我們把它放到方法名前煞烫,用點.
表示從屬關(guān)系。在方法體中软棺,用關(guān)鍵字this
對本體進(jìn)行調(diào)用红竭。和普通方法一樣,如果有返回值喘落,在方法后面跟上返回類型茵宪,我這里沒有返回值,所以直接省略了瘦棋。
還有一點很神奇的是稀火,我們可以允許目標(biāo)類接受null。不是說對null進(jìn)行擴展赌朋,而是可以設(shè)置目標(biāo)類為一個可以為空的對象凰狞。再舉一個栗子,也是我們很常用的功能:
fun Any?.string() : String = if(this == null) "null obj" else toString()
var a = 1
toast("hello, ${a.string()}")
var b : View? = null
toast("hello, ${b.string()}")
// 輸出
Toast msg : hello, 1
Toast msg : hello, null obj
在這里我們對Any
進(jìn)行擴展沛慢,它在konlin中類似于java中的Object
赡若,所有的類都繼承與它,我們給它擴展了一個string()
方法团甲。還記得嗎逾冬,類型后面跟問號?
表示可為空。在這里當(dāng)目標(biāo)為null
時,我們返回了一個字符串身腻,看一下調(diào)用产还,再看一下輸出,完全和預(yù)想的一樣嘀趟。
kotlin中其實已經(jīng)默認(rèn)對toString方法進(jìn)行了處理脐区,如果是空,則會返回字符串null她按。這其實很多時候不符合我們的需求牛隅,我們可以自己擴展一下,將返回值改為空字符串就好尤溜。
fun Any?.string() : String = if(this == null) "" else toString()
二倔叼、擴展屬性(extension property)
擴展屬性和擴展方法類似,是對目標(biāo)類的屬性進(jìn)行擴展宫莱。擴展屬性也會有set
和get
方法丈攒,并且要求實現(xiàn)這兩個方法,不然會提示編譯錯誤授霸。因為擴展并不是在目標(biāo)類上增加了這個屬性巡验,所以目標(biāo)類其實是不持有這個屬性的,我們通過get
和set
對這個屬性進(jìn)行讀寫操作的時候也不能使用field
指代屬性本體碘耳∠陨瑁可以使用this
,依然表示的目標(biāo)類辛辨。
// 擴展了一個屬性paddingH
var View.panddingH : Int
get() = (paddingLeft + paddingRight) / 2
set(value) {
setPadding(value, paddingTop, value, paddingBottom)
}
// 設(shè)置值
text.panddingH = 100
在栗子中捕捂,我們首先給View擴展了一個屬性paddingH
,并給屬性增加了set
和get
方法斗搞,然后再activity中通過textview調(diào)用指攒。
三、靜態(tài)擴展
-
kotlin中的靜態(tài)用關(guān)鍵字
companion
表示僻焚,而且它不是修飾屬性或方法允悦,而是定義一個方法塊,在方法塊中的所有方法和屬性都是靜態(tài)的虑啤,這樣就將靜態(tài)部分統(tǒng)一包裝了起來隙弛。靜態(tài)部分的訪問和java一致,直接使用類名+靜態(tài)屬性/方法名就可以// 定義靜態(tài)部分 class Extension { companion object part{ var name = "Extension" } } // 通過類名+屬性名直接調(diào)用 toast("hello, ${Extension.name}") // 輸出 Toast msg : hello, Extension
上面栗子中狞山,
companion object
一起是修飾關(guān)鍵字全闷,part
是方法塊的名稱。其中萍启,方法塊名稱part
可以省略总珠,如果省略的話,默認(rèn)缺省名為Companion
-
靜態(tài)的擴展和普通的擴展類似,但是在目標(biāo)類要加上靜態(tài)方法塊的名稱姚淆,所以如果我們要對一個靜態(tài)部分?jǐn)U展,就要先知道靜態(tài)方法塊的名稱才行屡律。
class Extension { companion object part{ var name = "Extension" } } // part為靜態(tài)方法塊名稱 fun Extension.part.upCase() : String{ return name.toUpperCase() } // 調(diào)用一下 toast("hello, ${Extension.name}") toast("hello, ${Extension.upCase()}") //輸出 Toast msg : hello, Extension Toast msg : hello, EXTENSION
四腌逢、引用
在AS中,如果我們使用擴展方法和擴展屬性超埋,大部分情況下會自動提示導(dǎo)入import
搏讶,但有時候如果沒有提示,就需要手動import
一下了霍殴。擴展的import
路徑為:包名+方法名/屬性名媒惕,比如我最先創(chuàng)建的擴展方法toast
,其實文件全部是這樣的
package com.study.jcking.weatherkotlin.exec
import android.content.Context
import android.util.Log
import android.widget.Toast
/**
* Created by Jcking on 2017/6/3.
*/
fun Context.toast(msg : String){
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
Log.d("text", "Toast msg : $msg")
}
可見来庭,toast方法
沒有在類內(nèi)部妒蔚,而是與包名同級,當(dāng)然這不是絕對月弛,只是習(xí)慣這樣寫肴盏,那我們引用的時候就這樣寫import
import com.study.jcking.weatherkotlin.exec.toast
五、最后
以上就是個人學(xué)習(xí)擴展的一些總結(jié)帽衙,東西不多菜皂,但是感覺是kotlin中很重要的一部分。他讓我們的代碼更簡潔厉萝,更優(yōu)雅恍飘,而且功能定位更準(zhǔn)確、更清晰谴垫。再有章母,就是感覺一大波util要下崗了~
最后拋出個問題罪帖,暫時還沒有搞明白但两,希望小伙伴們幫我解惑:如果我將擴展沒有放在包名同級,而是放在一個類的內(nèi)部羽嫡,在語法上是完全沒有問題的肢专,但是類外部調(diào)用卻好像不行了舞肆。請問是它失去了對外部的可見性,還是我的調(diào)用方式有問題博杖?歡迎討論指教椿胯,先行謝過!剃根!
更新:2017年6月4日
問題已經(jīng)找到資料了哩盲,確實是不行的,請看我下一篇筆記: Kotlin學(xué)習(xí)筆記(8)- 擴展(續(xù))
Extension類,包package com.study.jcking.weatherkotlin.exec
package com.study.jcking.weatherkotlin.exec
class Extension {
companion object part{
var name = "Extension"
}
fun Context.toast(msg : String){
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
Log.d("text", "Toast msg : $msg")
}
}
調(diào)用類廉油,包package com.study.jcking.weatherkotlin
package com.study.jcking.weatherkotlin
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
toast("hello, ${Extension.upCase()}") // 這里toast報錯惠险,編譯錯誤,無法調(diào)用
}
}