網站首頁 編程語言 正文
前言
在這一節為大家繼續帶來 Kotlin 中的一些高級的內容:Kotlin 中的 Kotlin 擴 展(Extensions)。
Kotlin 能夠擴展一個類的新功能而無需繼承該類。 例如,你可以為一個你不 能修改的來自第三方庫中的類編寫一個新的函數。 這個新增的函數就像那個 原始類本來就有的函數一樣,可以用普通的方法調用。 這種機制稱為 擴展 函數 。此外,也有 擴展屬性 , 允許你為一個已經存在的類添加新的屬 性。想想是不是感覺很瘋狂呢?那接下來就往我們開啟這種瘋狂吧。
一、擴展方法
Kotlin 的擴展函數可以讓你作為一個類成員進行調用的函數,但是是定義在這 個類的外部。這樣可以很方便的擴展一個已經存在的類,為它添加額外的方 法。在 Kotlin 源碼中,有大量的擴展函數來擴展 Java,這樣使得 Kotlin 比 Java 更方便使用,效率更高。
1.擴展方法的原型
2.擴展方法的使用
在 Kotlin 中使用
class Jump {
fun test() {
println("jump test")
//在被擴展的類中使用
doubleJump(1f)
}
}
fun Jump.doubleJump(howLong: Float): Boolean {
println("jump:$howLong")
println("jump:$howLong")
return true
}
Jump().doubleJump(2f)
//在被擴展類的外部使用
Jump().test()
在 Java 中使用
在 Java 中調用 Kotlin 擴展,需要通過擴展所在的文件名+.的方式進行調用:
KotlinExtensionKt.doubleJump(new Jump(), 2.0f);
另外,需要注意的是我們需要為這個方法傳遞它被擴展類的對象來作為接受者,為什么要傳遞接 受者對象,這是由擴展的實現原理所決定的,在原理解析部分會講解。
二、Kotlin擴展方法實現原理
在體驗到 Kotlin 擴展帶個我們高效編程的同時,我們不禁要問自己幾個問 題:
Kotlin 的擴展是怎么實現的?
Kotlin 的擴展會不是有性能問題?
接下來我們就從 Kotlin 反編譯出 Java 代碼上來一探究竟:
fun main() {
val test = mutableListOf(1, 2, 3)
test.swap(1, 2)
println(test)
}
fun MutableList<Int>.swap(index1: Int, index2: Int) {
val tmp = this[index1]
this[index1] = this[index2]
this[index2] = tmp
}
反編譯出 Java 源碼
public final class KotlinExtensionKt {
public static final void main() {
List test = CollectionsKt.mutableListOf(new Integer[]{1, 2, 3});
swap(test, 1, 2);
boolean var1 = false;
System.out.println(test);
}
// $FF: synthetic method
public static void main(String[] var0) {
main();
}
public static final void swap(@NotNull List $this$swap, int index1,
int index2) {
Intrinsics.checkParameterIsNotNull($this$swap, "$this$swap");
int tmp = ((Number)$this$swap.get(index1)).intValue();
$this$swap.set(index1, $this$swap.get(index2));
$this$swap.set(index2, tmp);
}
}
從反編譯出的 Java 源碼分析,擴展函數的實現非常簡單,它沒有修改接受者類型的成員, 僅僅 是通過靜態方法來實現的。所以我們不必擔心擴展函數會帶來額外的性能消耗。
三、泛型擴展方法
為了考慮到擴展函數的通用型,我們可以借助上面課程中學習到的泛型,來 為擴展方法進行泛型化改造,以 fun MutableList.swap(index1: Int, index2: Int)為例,接下來我們為它進行泛型化改造:
//泛型化擴展函數
fun <T> MutableList<T>.swap1(index1: Int, index2: Int) {
val tmp = this[index1]
this[index1] = this[index2]
this[index2] = tmp
}
val test2 = mutableListOf("Android Q", "Android N", "Android M")
test2.swap1(0,1)
println(test2)
四、擴展屬性
擴展屬性提供了一種方法能通過屬性語法進行訪問的 API 來擴展。盡管它們 被叫做屬性,但是它們不能擁有任何狀態,它不能添加額外的字段到現有的 Java 對象實例。
//為 String 添加一個 lastChar 屬性,用于獲取字符串的最后一個字符
val String.lastChar: Char get() = this.get(this.length - 1)
///為 List 添加一個 last 屬性用于獲取列表的最后一個元素,this 可以省略
val <T>List<T>.last: T get() = get(size - 1)
val listString = listOf("Android Q", "Android N", "Android M")
println("listString.last${listString.last}")
五、為伴生對象添加擴展
如果一個類定義了伴生對象 ,那么我們也可以為伴生對象定義擴展函數與屬性:
class Jump {
companion object {}
}
fun Jump.Companion.print(str: String) {
println(str)
}
Jump.print("伴生對象的擴展")
就像伴生對象的常規成員一樣:可以只使用類名作為限定符來調用伴生對象 的擴展成員;
六、Kotlin 中常用的擴展
在 Kotlin 的源碼中定義了大量的擴展,比如:let,run,apply,了解并運用這些 函數能幫我們提高編碼效率,接下來就往我們一起揭開這些擴展函數的神秘面紗吧!
let 擴展
函數原型:
fun <T, R> T.let(f: (T) -> R): R = f(this)
let 擴展函數的實際上是一個作用域函數,當你需要去定義一個變量在一個特定的作用域范圍內,那么let 函數是一個不錯的選擇;let 函數另一個作用就 是可以避免寫一些判斷 null 的操作。
fun testLet(str: String?) {
//限制 str2 的作用域
str.let {
val str2 = "let 擴展"
println(it + str2)
}
// println(str2)//報錯
//避免為 null 的操作
str?.let {
println(it.length)
}
}
run 擴展
函數原型:
fun <T, R> T.run(f: T.() -> R): R = f()
run 函數只接收一個 lambda 函數為參數,以閉包形式返回,返回值為最后一 行的值或者指定的 return 的表達式,在 run 函數中可以直接訪問實例的公有屬性和方法。
data class Room(val address: String, val price: Float, val size: Float)
fun testRun(room: Room) {
room.run {
println("Room:$address,$price,$size")
}
}
apply 擴展
函數原型:
fun <T> T.apply(f: T.() -> Unit): T { f(); return this }
apply 函數的作用是:調用某對象的 apply 函數,在函數范圍內,可以任意調 用該對象的任意方法,并返回該對象。
從結構上來看 apply 函數和 run 函數很像,唯一不同點就是它們各自返回的 值不一樣,run 函數是以閉包形式返回最后一行代碼的值,而 apply 函數的返 回的是傳入對象的本身。
apply 一般用于一個對象實例初始化的時候,需要對對象中的屬性進行賦值。 或者動態 inflate 出一個 XML 的 View 的時候需要給 View 綁定數據也會用 到,這種情景非常常見。
fun testApply() {
ArrayList<String>().apply {
add("testApply")
add("testApply")
add("testApply")
println("$this")
}.let { println(it) }
}
七、案例
使用 Kotlin 擴展為控件綁定監聽器減少模板代碼
定義擴展
//為 Activity 添加 find 擴展方法,用于通過資源 id 獲取控件
fun <T : View> Activity.find(@IdRes id: Int): T {
return findViewById(id)
}
//為 Int 添加 onClick 擴展方法,用于為資源 id 對應的控件添加 onClick 監聽
fun Int.onClick(activity: Activity, click: () -> Unit) {
activity.find<View>(this).apply {
setOnClickListener {
click()
}
}
}
應用擴展
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val textView = find<TextView>(R.id.test)
R.id.test.onClick(this) {
textView.text = "Kotlin 泛型"
}
}
}
在這個案例中我們通過兩個擴展方法,大大減少了我們在獲取控件,以及為 控件綁定 onClick 監聽時候的模板代碼,而且代碼可讀性更高,更加直觀, 這便是 Kotlin 擴展的強大之處。
Kotlin 擴展的應用案例遠不止這些,需要大家在下去之后能夠活學活用,來發 掘屬于你自己的 Kotlin 擴展吧。
原文鏈接:https://blog.csdn.net/m0_58941767/article/details/127043408
相關推薦
- 2023-04-02 Android自定義View實現動畫效果詳解_Android
- 2022-04-12 解決error: failed to push some refs to ‘xxx(遠程倉庫)‘
- 2023-01-30 C++指針和數組:字符和字符串、字符數組的關聯和區別_C 語言
- 2022-09-06 關于react+antd樣式不生效問題的解決方式_React
- 2022-06-09 Python中re模塊的元字符使用小結_python
- 2022-05-29 解決Docker容器下不能使用vim命令的問題_docker
- 2022-05-05 Entity?Framework使用LINQ操作實體_實用技巧
- 2022-06-17 C語言深入講解函數參數的使用_C 語言
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支