網(wǎng)站首頁 編程語言 正文
算數(shù)運(yùn)算操作符重載
在kotlin中我定義一個(gè)類
data class Point(val x: Int, val y: Int)
然后實(shí)例化兩個(gè)對(duì)象
val p1 = Point(3,5)
val p2 = Point(5,7)
想表示p1的元素x加上p2的元素x,p1的元素y,加上p2的元素y.然后輸出一個(gè)p3.
val p3 = Point(p1.x + p2.x, p2.y + p2.y)
以上這種寫法沒有任何問題。不過我們可以利用Kotlin擴(kuò)展函數(shù)簡(jiǎn)化上面的操作,我們給Point增加一個(gè)plus,并附加operator關(guān)鍵字。(增加operator的關(guān)鍵字是為了區(qū)分plus并不是一個(gè)普通的成員方法)
data class Point(val x: Int, val y: Int) {
operator fun plus(other: Point): Point {
return Point(x + other.x, y + other.y)
}
}
接下來再來實(shí)現(xiàn)上面的需求.
val p3 = p1 + p2
這樣表達(dá)起來更簡(jiǎn)潔了。 另外我們可以把plus作為Point的擴(kuò)展方法
data class Point(val x: Int, val y: Int)
operator fun Point.plus(other: Point): Point {
return Point(x + other.x, y + other.y)
}
這種場(chǎng)景適用于Point存在于一個(gè)三方庫,我們并能修改其中的內(nèi)容. Kotlin中提供了以下操作符的重載. 只需要實(shí)現(xiàn)對(duì)應(yīng)的方法即可。
之前我們定一個(gè)了plus,參數(shù)是Point,實(shí)際上對(duì)于個(gè)操作符重載并不局限于同一種類型,接下來我們來定一個(gè)times,允許你去擴(kuò)展Ponit.
data class Point(val x: Int, val y: Int)
operator fun Point.times(scale: Double): Point {
return Point((x * scale).toInt(), (y * scale).toInt())
}
fun main(args: Array<String>) {
val p = Point(10, 20)
println(p * 1.5)
}
注意kotlin不支持交換性,例如我這里寫成1.5 * p這里是不允許的。除非你去定一個(gè)
operator fun Double.times(p: Point): Point
返回類型同樣也可以不是同一個(gè)類型,例如, 定義一個(gè)對(duì)char類型重載*操作符重復(fù)count后返回一個(gè)string.
operator fun Char.times(count: Int): String {
return toString().repeat(count)
}
fun main(args: Array<String>) {
println('a' * 3)
}
復(fù)合運(yùn)算操作符重載
我們?cè)诰幊踢^程中通常會(huì)去把這種寫法p = p + p1 寫成 p += p1 這種簡(jiǎn)化寫法,在kotlin中同樣也支持這種+=操作符自定義操作。這種自定義運(yùn)算操作符在什么場(chǎng)景下使用呢? 舉個(gè)例子,我們定義集合
val numbers = ArrayList<Int>()
numbers += 42
println(numbers[0])
以上寫法會(huì)感覺更加簡(jiǎn)潔。 我們?cè)诩现卸x操作符重載方法plusAssign(這里還有minusAssign,?timesAssign等等)
operator fun <T> MutableCollection<T>.plusAssign(element: T) {
this.add(element)
}
不過kotlin-stblib庫已經(jīng)幫你實(shí)現(xiàn)好了關(guān)于集合的類似操作. 在集合中+,-會(huì)累加集合原始后返回一個(gè)新的集合,如果使用+=,-=, 集合是mutable,會(huì)在本集合直接修改內(nèi)容,如果集合是read-only,會(huì)返回一個(gè)拷貝后的修改集合。(這意味著如果集合是read-only,它的聲明必須要是var, 不然它不能接受新返回拷貝后的修改集合). 你可以使用單獨(dú)的元素或者集合(類型必須一致)進(jìn)行復(fù)合運(yùn)算符操作和算數(shù)運(yùn)算符.
val list = arrayListOf(1, 2)
list += 3
val newList = list + listOf(4, 5)
println(list)
result : [1, 2, 3]
println(newList)
result : [1, 2, 3, 4, 5]
一元運(yùn)算操作符重載
我們?cè)诰幊踢^程中使用類似++a, a++, --a, a--同樣支持運(yùn)算符重載。僅僅需要重寫下面的操作符函數(shù)即可
舉個(gè)例子
operator fun BigDecimal.inc() = this + BigDecimal.ONE
fun main(args: Array<String>) {
var bd = BigDecimal.ZERO
println(bd++)
println(++bd)
}
這里注意到我只定一個(gè)inc(),同時(shí)也是支持bd++和++bd.
比較操作符重載
kotlin中還支持==,?!=,?>,?<操作符重載. 對(duì)于==,?!=我們重寫equals方法. 這里還是拿Point來舉栗子
data class Point(val x: Int, val y: Int)
我們這里聲明成了data類,這個(gè)關(guān)鍵字加上了編譯器會(huì)自動(dòng)幫你實(shí)現(xiàn)equals方法,我們現(xiàn)在去掉,看看自己去寫equals怎么寫
class Point(val x: Int, val y: Int) {
override fun equals(obj: Any?): Boolean {
if (obj === this) return true //1
if (obj !is Point) return false
return obj.x == x && obj.y == y
}
}
fun main(args: Array<String>) {
println(Point(10, 20) == Point(10, 20))
println(Point(10, 20) != Point(5, 5)) //2
println(null == Point(1, 2))
}
這里我們需要關(guān)注一個(gè)//1 obj === this,這個(gè)===操作符是比較兩個(gè)對(duì)象的引用是否一致,實(shí)際上和java中的==是一樣的。 之前我們提到的操作符重載都會(huì)加上一個(gè)operator關(guān)鍵字,這里為什么是override?因?yàn)樗貙懥薃ny.class的equals方法.
這里看下//2!= 其實(shí)就是equals結(jié)果的取反. 除了=和!=之外這里還有>和<, 通過重寫compareTo可以實(shí)現(xiàn)
class Person(
val firstName: String, val lastName: String
) : Comparable<Person> {
override fun compareTo(other: Person): Int {
return compareValuesBy(this, other,
Person::lastName, Person::firstName)
}
}
fun main(args: Array<String>) {
val p1 = Person("Alice", "Smith")
val p2 = Person("Bob", "Johnson")
println(p1 < p2)
}
這里的compareValuesBy順便說說,它是kotlin-stblib提供的擴(kuò)展函數(shù)
集合和區(qū)域的約定
在kotlin中我們可以使用類似于操作數(shù)組的方法操作集合,例如a[b]這種. 對(duì)于其它類,可以自定義操作符實(shí)現(xiàn)類似的操作
operator fun Point.get(index: Int): Int {
return when(index) {
0 -> x
1 -> y
else ->
throw IndexOutOfBoundsException("Invalid coordinate $index")
}
}
fun main(args: Array<String>) {
val p = Point(10, 20)
println(p[1])
}
我們對(duì)于賦值操作同樣也可以通過自定義operator
data class MutablePoint(var x: Int, var y: Int)
operator fun MutablePoint.set(index: Int, value: Int) {
when(index) {
0 -> x = value
1 -> y = value
else ->
throw IndexOutOfBoundsException("Invalid coordinate $index")
}
}
fun main(args: Array<String>) {
val p = MutablePoint(10, 20)
p[1] = 42
println(p)
}
另外一個(gè)知識(shí)點(diǎn)是自定義in操作符
in對(duì)于的contains函數(shù),判斷一個(gè)元素是否屬于一個(gè)范圍里.
data class Point(val x: Int, val y: Int)
data class Rectangle(val upperLeft: Point, val lowerRight: Point)
operator fun Rectangle.contains(p: Point): Boolean {
return p.x in upperLeft.x until lowerRight.x &&
p.y in upperLeft.y until lowerRight.y
}
fun main(args: Array<String>) {
val rect = Rectangle(Point(10, 20), Point(50, 50))
println(Point(20, 30) in rect)
println(Point(5, 5) in rect)
}
迭代運(yùn)算符重載
我們平時(shí)使用的
for (x in list) { ... }
將被轉(zhuǎn)換為 list.iterator() 的調(diào)用,然后重復(fù)調(diào)用 hasNext 和 next 方法,就像在 Java 中一樣。 請(qǐng)注意,在 Kotlin 中,它也是一種約定,這意味著可以將迭代器方法定義為擴(kuò)展。這就解釋了為什么可以迭代常規(guī) Java 字符串:kotlin-stblib 在 Char-Sequence(String 的超類)上定義了一個(gè)擴(kuò)展函數(shù)迭代器:
operator fun CharSequence.iterator(): CharIterator
>>> for (c in "abc") {}
其它類型也可以通過自定義iterator實(shí)現(xiàn)自己類特定的操作。
import java.util.Date
import java.time.LocalDate
operator fun ClosedRange<LocalDate>.iterator(): Iterator<LocalDate> =
object : Iterator<LocalDate> {
var current = start
override fun hasNext() =
current <= endInclusive
override fun next() = current.apply {
current = plusDays(1)
}
}
fun main(args: Array<String>) {
val newYear = LocalDate.ofYearDay(2017, 1)
val daysOff = newYear.minusDays(1)..newYear
for (dayOff in daysOff) { println(dayOff) }
}
解構(gòu)聲明
這個(gè)操作可以分解一個(gè)對(duì)象中成員,例如
>>> val p = Point(10, 20)
>>> val (x, y) = p
>>> println(x)
10
>>> println(y)
20
解構(gòu)聲明看起來有點(diǎn)像變量聲明,不過它組合了多個(gè)變量值。實(shí)際上它在kotlin中也屬于自定義操作符.去解構(gòu)多個(gè)變量需要定義componentN,N是變量的位置.
class Point(val x: Int, val y: Int) {
operator fun component1() = x
operator fun component2() = y
}
對(duì)于data類,解構(gòu)已經(jīng)幫你聲明好了 另外解構(gòu)聲明還可以用在循環(huán)中
fun printEntries(map: Map<String, String>) {
for ((key, value) in map) {
println("$key -> $value")
}
}
fun main(args: Array<String>) {
val map = mapOf("Oracle" to "Java", "JetBrains" to "Kotlin")
printEntries(map)
}
Map中包含了擴(kuò)展方法component1,component2返回key和value. 實(shí)際上你可以將上面的循環(huán)部分翻譯成
for (entry in map.entries) {
val key = entry.component1()
val value = entry.component2()
// ...
}
總結(jié)
原文鏈接:https://juejin.cn/post/7087129138070290463
相關(guān)推薦
- 2022-12-09 python淺拷貝與深拷貝使用方法詳解_python
- 2022-12-24 Android設(shè)置Padding和Margin(動(dòng)態(tài)/靜態(tài))的方法實(shí)例_Android
- 2023-01-19 使用python檢查值是否已經(jīng)存在于字典列表中_python
- 2022-02-13 error C4996:‘scanf‘:This function or variable may
- 2022-11-09 Go語言數(shù)據(jù)結(jié)構(gòu)之二叉樹可視化詳解_Golang
- 2023-02-07 C#實(shí)現(xiàn)加密bat文件的示例詳解_C#教程
- 2022-09-30 python實(shí)現(xiàn)圖像邊緣檢測(cè)_python
- 2022-04-18 pyinstaller打包后,配置文件無法正常讀取的解決_python
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支