網(wǎng)站首頁 編程語言 正文
一、擴展函數(shù)
不少現(xiàn)代高級編程語言中有擴展函數(shù)這個概念,Java卻一直以來都不支持這個功能,Kotlin對擴展函數(shù)有了很好的支持。
擴展函數(shù)表示即使在不修改某個類的源碼的情況下,仍然可以打開這個類,向該類添加新的函數(shù)。
比如有一個功能:一段字符串中可能包含字母、數(shù)字和特殊符號等字符,現(xiàn)在我們希望統(tǒng)計字符串中字母的數(shù)量,要怎么實現(xiàn)這個功能?如果按照一般的編程思維,可能會很自然的寫出如下函數(shù):
object StringUtil{
fun lettersCount(str:String):Int{
var count=0
for(char in str){
if(char.isLetter()){
count++
}
}
return count
}
}
這里先定義了一個StringUtil單例類,然后在這個單例類中定義一個lettersCount()函數(shù),該函數(shù)接收一個字符串參數(shù)。在lettersCount()方法中,我們使用for-in循環(huán)去遍歷字符串中的每一個字符。如果該字符是一個字母的話,那么計數(shù)器加1,最終返回計數(shù)器的值。
現(xiàn)在我們需要統(tǒng)計某個字符串中的字母數(shù)量時,只需要編寫如下代碼:
val str="ABCdsw1242"
val Count = StringUtil.lettersCount(str)
這種寫法可以正常工作,這也是Java編程中的標準實現(xiàn)思維,但有了擴展函數(shù)之后就不一樣了,我們可以使用一種更加面向思維來實現(xiàn)這個功能,比如說lettersCount()函數(shù)添加到String類當中。
我們先來學習一下定義擴展函數(shù)的語法結(jié)構(gòu),如下所示:
fun ClassName.methodName(param1:Int,param2:Int):Int{
return 0
}
想定義普通的函數(shù),定義擴展函數(shù)只需要在函數(shù)名的前面加上一個ClassName.的語法結(jié)構(gòu),就表示將該函數(shù)添加到指定類當中。
接下來使用擴展函數(shù)的方式來優(yōu)化剛才的統(tǒng)計功能。
由于我們希望向String類中添加一個擴展函數(shù),因此需要先創(chuàng)建一個String.kt文件。文件名雖然沒有固定的要求,但是我建議向哪個類中添加擴展函數(shù),就定義一個同名的Kotlin文件,這樣便于你以后查找。當前,擴展函數(shù)也是可以定義在任何一個現(xiàn)有類當中的,并不一定非要創(chuàng)建新文件。不過通常來說,最好將它定義成頂層方法,這樣可以讓擴展函數(shù)擁有全局的訪問域。
現(xiàn)在在String.kt文件中編寫如下代碼:
fun String.lettersCount():Int{
var count=0
for(char in this){
if(char.isLetter()){
count++
}
}
return count
}
注意這里的代碼變化,現(xiàn)在我們將lettersCount()方法定義成了String類的擴展函數(shù),那么函數(shù)中就自動擁有了String實例的上下文。因此lettersCount()函數(shù)就不再需要接收一個字符串參數(shù)了,而是直接遍歷this即可,因為現(xiàn)在this就代表著字符串本身。
定義好了擴展函數(shù)之后,統(tǒng)計某個字符串中的字母數(shù)量只需要這樣寫即可:
val count="ABCdsw1242".lettersCount()
這樣看上去是String類中自帶了lettersCount()方法一樣。
擴展函數(shù)在很多情況下可以讓API變得更加簡潔、豐富,更加面向?qū)ο蟆N覀冊俅我許tring類為例,這是一個final類,任何一個類都不可以繼承它,也就是說它的API只有固定的那些而已,至少在Java中就是如此。然而到了Kotlin中就不一樣了,我們可以向Kotlin類中擴展任何函數(shù),使他的API變得更加豐富。比如,你會發(fā)現(xiàn)Kotlin中的String甚至還有reverse()函數(shù)用于反轉(zhuǎn)字符串,capitalize()函數(shù)用于對首字母進行大寫,等等,這都是Kotlin語言自帶的一些擴展函數(shù)。
二、運算符重載
在Java中有許多語言內(nèi)置的運算符關(guān)鍵字,如+,-,*,/,%,++,–。而Kotlin允許我們將所有的運算符甚至其他的關(guān)鍵字進行重載,從而拓展這些運算符和關(guān)鍵字的用法。
我們基本上都使用過加減乘除這種四則運算符,在編程語言里面,兩個數(shù)字相加表示求這兩個數(shù)字之和,兩個字符串相加表示對這兩個字符串進行拼接。但是在Kotlin語言中,kotlin運算符重載卻允許我們讓任意兩個對象相加,或者進行更多其他的運算操作。
運算符重載使用的是operator關(guān)鍵字,只要在指定函數(shù)的前面加上operator關(guān)鍵字,就可以實現(xiàn)運算符重載的功能了。但問題是在于這個指定函數(shù)是什么?這是運算符重載里面比較復(fù)雜的一個問題,因為不同的運算符對應(yīng)的重載函數(shù)也是不同的。比如說加號運算符對應(yīng)的是plus()函數(shù),減號運算符對應(yīng)的是minus()函數(shù)。
我們這里還是以加號運算符為例,如果想要實現(xiàn)讓兩個對象相加的功能,那么它的語法結(jié)構(gòu)如下:
class obj{
operator fun plus(obj:Obj):Obj{
//處理相加的邏輯
}
}
在上述的語法結(jié)構(gòu)中,關(guān)鍵字operator和函數(shù)名plus都是固定不變的,而接收的參數(shù)和函數(shù)返回值可以根據(jù)你的邏輯自行設(shè)定。那么上述代碼就表示一個Obj對象可以與另一個Obj對象相加,最終返回一個新的Obj對象。對應(yīng)的調(diào)用方式如下:
val obj1=Obj()
val obj2=Obj()
val obj3=obj1+obj2
這種obj1+obj2的語法其實就是Kotlin給我們提供的一種語法糖,它會在編譯的時候被轉(zhuǎn)換成obj1.plus(obj2)的調(diào)用方式。
舉一個例子實現(xiàn)讓兩個Money對象相加
首先定義Money類的結(jié)構(gòu),這里讓Money的主構(gòu)造函數(shù)接收一個value參數(shù),用于表示錢的金額。創(chuàng)建Money.kt文件,代碼如下所示:
class Money(val value:Int)
定義好了Money類的結(jié)構(gòu),接下來我們就使用運算符來重載實現(xiàn)讓兩個Money對象相加的功能:
class Money(val value:Int) {
operator fun plus(money: Money):Money{
val sum=value+money.value
return Money(sum)
}
}
可以看到,這里使用了operator關(guān)鍵字來修飾plus()函數(shù),這是必不可少的。在plus()函數(shù)中,我們將當前Money對象的value和參數(shù)傳入的Money對象的value相加,然后將得到的和傳入給一個新的Money對象并將該對象返回。這樣兩個Money對象就可以相加了。
我們可以使用如下代碼進行測試
val money1 = Money(5)
val money2 = Money(10)
val money3=money1+money2
println(money3.value)
最終結(jié)果為15
Money對象能夠直接和數(shù)字相加,因為Kotlin允許我們對同一個運算符進行多重重載,代碼如下:
class Money(val value:Int) {
operator fun plus(money: Money):Money{
val sum=value+money.value
return Money(sum)
}
//對同一個運算符進行多重重載
operator fun plus(newValue:Int):Money{
val sum=value+newValue
return Money(sum)
}
}
這里我們又重載了一個plus()函數(shù),不過這次接收的參數(shù)是一個整型數(shù)字,其他代碼基本一樣。
那么現(xiàn)在Money對象就擁有了和數(shù)字相加的能力:
val money1 = Money(5)
val money2 = Money(10)
val money3=money1+money2
val money4=money3+20
println(money4.value)
打印結(jié)果為35
Kotlin允許我們重載的運算符和關(guān)鍵字多達十幾個。表中列出了所有可能常用的可重載運算符和關(guān)鍵字對應(yīng)的語法糖表達式,以及它們會被轉(zhuǎn)換成的實際調(diào)用函數(shù)。如果想重載其中的某一種運算符或關(guān)鍵字,只要參考剛才加號運算符重載的寫法去實現(xiàn)就行了。
語法糖表達式 | 實際調(diào)用函數(shù) |
---|---|
a+b | a.plus(b) |
a-b | a.minus(b) |
a*b | a.times(b) |
a/b | a.div(b) |
a%b | a.rem(b) |
a++ | a.inc() |
a– | a.dec() |
+a | a.unaryPlus |
-a | a.unaryMinus |
!a | a.not |
a==b | a.equals(b) |
a>=b | a.compareTo(b) |
a…b | a.rangeTo(b) |
a[b] | a.get(b) |
a[b]=c | a.set(b,c) |
a in b | b.contains(a) |
注意,最后一個a in b的語法糖表達式對應(yīng)的實際調(diào)用函數(shù)是b.contains(a),a、b對象順序是反過來的。因為a in b表示判斷a是否在b當中,而b.contains(a)表示b是否包含a,因此這兩種表達式是等價的。
舉個例子,Kotlin中的String類就對contains()函數(shù)進行了重載,因此當我們判斷“hello”字符串中是否包含“he”子串時,首先可以這樣寫:
if("hello".contains("he")){
}
而借助重載的語法糖表達式,也可以這樣寫:
if("he" in "hello"){
}
結(jié)合學習的擴展函數(shù)以及運算符重載的知識,對以下功能進行優(yōu)化
fun getRandomLengthString(str:String):String{
val n=(1..20).random()
val builder=StringBuilder()
repeat(n){
builder.append(str)
}
return builder.toString()
}
其實這個函數(shù)的核心思想就是將傳入的字符串重復(fù)n次,而Kotlin能夠讓我們使用str*n這種寫法來表示讓str字符串重復(fù)n次,使語法更精簡。
要讓一個字符串可以乘以一個數(shù)字,那么肯定要在String類中重載乘號運算符才行,但是String類是系統(tǒng)提供的類,我們無法修改這個類的代碼。這個時候就可以借助擴展函數(shù)功能向String類中添加新函數(shù)了。
既然是向String類中添加擴展函數(shù),那么我們還是打開剛才創(chuàng)建的String.kt文件,然后加入如下代碼:
operator fun String.times(n:Int):String{
val builder=StringBuilder()
repeat(n){
builder.append(this)
}
return builder.toString()
}
首先,operator關(guān)鍵字肯定是必不可少的,然后是要重載乘號運算符,參考上面的表,如果要乘那么函數(shù)名必須是times,最后由于是定義擴展函數(shù),因此還要在方法名前面加上String.的語法結(jié)構(gòu)。在times()函數(shù)中,我們借助StringBuilder和repeat函數(shù)將字符串重復(fù)n次,最終將結(jié)果返回。
現(xiàn)在,字符串就有了和一個數(shù)字相乘的能力,比如執(zhí)行如下代碼:
val str="abc"*3
println(str)
最終打印結(jié)果是:abcabcabc。
現(xiàn)在我們就可以在getRandomLengthString()函數(shù)中使用這種寫法了
operator fun String.times(n:Int)=str*(1..20).random()
另外,必須說明的是,其實Kotlin的String類中已經(jīng)提供了一個用于將字符串重復(fù)n遍的repeat()函數(shù),因此times()函數(shù)還可以進一步精簡成如下形式:
operator fun String.times(n:Int)=repeat(n)
原文鏈接:https://blog.csdn.net/ChenYiRan123456/article/details/127893395
相關(guān)推薦
- 2023-04-12 Android同步屏障機制sync?barrier實例應(yīng)用詳解_Android
- 2023-07-31 el-input自動獲取焦點并選中值
- 2022-09-09 python中對開區(qū)間和閉區(qū)間的理解_python
- 2022-09-21 Flutter實現(xiàn)資源下載斷點續(xù)傳的示例代碼_Android
- 2022-07-17 C++深入講解引用的特點及與指針的區(qū)別_C 語言
- 2022-07-17 關(guān)于elasticsearch連接時斷時續(xù)以及Kibana出現(xiàn)server is not ready
- 2022-06-27 python?使用ctypes調(diào)用C/C++?dll詳情_python
- 2022-12-03 Python學習之列表和元組的使用詳解_python
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細win安裝深度學習環(huán)境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支