本文是對<<Kotlin in Action>>
的學習筆記,若是須要運行相應的代碼能夠訪問在線環境 try.kotlinlang.org,這部分的思惟導圖爲: java
Kotlin
中,咱們能夠經過
調用本身代碼中定義的函數,來實現
特定語言結構。這些功能與
特定的函數命名 相關,而不是與特定的類型綁定。例如,若是在你的類中定義了一個名爲
plus
的特殊方法,那麼按照約定,就能夠在該類的實例上使用
+
運算符,這種技術稱爲
約定。
由於由類實現的接口集是固定的,而Kotlin
不能爲了實現其餘接口而修改現有的類,所以通常 經過擴展函數的機制 來爲現有的類增添新的 約定方法,從而適應任何現有的Java
類。算法
在Kotlin
中,使用約定的最直接的例子就是 算術運算符,在Java
中,全套的算術運算符只能用於基本數據類型,+
運算符能夠與String
一塊兒使用。下面,咱們看一下在Kotlin
中,如何使用算術運算符來完成一些其它的事情。數組
假設已經有一個數據類Point
,它包含兩個成員變量,分別是x,y
點的座標值,咱們但願經過算術運算符+
對兩個Point
對象相加以後,可以獲得一個新的Point
對象,它的成員變量x,y
爲原有兩個Point
對象的x,y
之和。 ide
Point
類定義了一個擴展函數
plus
,這樣當咱們調用
first + second
,實際上執行的是
first.plus(second)
方法來獲得一個新的
Point
對象。這裏須要注意的是:用於重載運算符的全部函數都須要
用 operator 關鍵字來標記,用來表示你打算 把這個函數做爲相應的約定的實現。
全部可重載的二元算術運算符以下,自定義類型的運算符,基本上和標準數字類型的運算符有着相同的優先級。函數
a * b
:times
a / b
:div
a % b
:mod
a + b
:plus
a - b
:minus
Java
調用Kotlin
運算符很是容易,只須要像普通函數同樣調用便可,例如上面的plus
方法。Kotlin
調用Java
的時候,對於與Kotlin
約定匹配的函數(不要求使用operator
修飾符,可是參數須要匹配名稱和數量)均可以使用運算符語言來調用。若是Java
類定義了一個知足需求的函數,可是起了一個不一樣的名稱,能夠經過定義一個擴展函數來修正這個函數名用來替代現有的Java
方法。Kotlin
沒有爲標準數字類型Int
,Long
等定義任何位運算符,所以也不容許你爲自定類型定義它們。相反,它使用中綴調用語法的函數,能夠爲自定義類型定義類似的函數,下面咱們爲Point
添加一個and
,用於執行位運算。 學習
operator
關鍵字來聲明,而是用
infix
來定義一箇中綴調用語法的函數,其它執行位運算的函數包括:
shl
、
shr
、
ushr
、
and
、
or
、
xor
和
inv
。
當在定義像plus
這樣的函數,Kotlin
不止支持+
號運算,也支持像+=
這樣的 複合賦值運算符。 spa
first
要聲明爲
var
。在一些狀況下,定義
+=
運算符能夠
修改使用它的變量所引用的對象,但不會從新分配引用,將一個元素添加到可變集合,就是一個很好的例子:
Unit
,名爲
plusAssign
的函數,
Kotlin
將會在用到
+=
運算符的地方使用它,其它二元運算符也有命名類似的對應函數:
minusAssign
、
timesAssign
等。
當在代碼中用到+=
的時候,理論上plus
和plusAssign
均可能會被調用,若是兩個函數都有定義而且適用,那麼編譯器就會報錯,例以下面這樣的定義: 3d
first
,這樣plus
運算符就再也不適用。plus
和plusAssign
運算。若是一個類是 不可變的,那就應該只提供返回一個新值的運算;若是一個類是 可變的,例如構建器,那麼只須要提供plusAssign
和相似的運算符就夠了。Kotlin
的標準庫支持集合的這兩種方法:code
+
和-
運算符老是返回一個新的集合+=
和-=
運算符用於可變集合時,始終在一個地方修改它們;而它們用於只讀集合時,會返回一個修改過的副本。做爲它們的運算數,可使用單個元素,也可使用元素類型一致的其它集合: component
重載一元運算的過程和前面看到的方式相同:用預先定義的一個名稱來聲明函數,並用修飾符operator
標記。下面的例子中重載了-a
運算符:
+a
:unaryPlus
-a
:unaryMinus
!a
:not
++a/a++
:inc
--a/a--
:dec
當你定義inc
和dec
函數來重載自增和自減的運算符時,編譯器自動支持與普通數字類型的前綴、後綴自增運算符相同的語義。例如後綴運算會先返回變量的值,而後才執行++
操做。
與算術運算符同樣,在Kotlin
中,能夠對任何對象使用比較運算符(==
、!=
、>
和<
),而不只僅限於基本數據類型。
若是在Kotlin
中使用==/!=
運算符,它將被轉換成equals
方法的調用,和其餘運算符不一樣的是,==
和!=
能夠用於可空運算數,比較a == b
會檢查a
是否爲飛空,若是不是就調用a.equals(b)
,完整的調用以下所示:
a?.equals(b) ?: (b == null)
複製代碼
對於data
修飾的數據類,equals
的實現將會由編譯器自動生成,若是須要手動實現,能夠參考下面的作法:
true
false
equals
函數之因此被標記爲override
,這是由於這個方法的實現是在Any
類中定義的,而operator
關鍵字在基本方法中已經標記了。同時,equals
不能實現爲擴展函數,由於繼承自Any
類的實現始終優先於擴展函數。
在Kotlin
中,對於實現了Comparable
接口中定義的compareTo
方法的類能夠按約定調用,比較運算符<、>、<=、>=
的使用將被轉換爲compareTo
,compareTo
的返回類型必須爲int
,也就是說p1 < p2
表達式等價於p1.compareTo(p2) < 0
。
下面,咱們定義一個Person
類,讓其根據年齡來比較大小:
Kotlin
標準庫函數中的
compareValuesBy
函數來簡潔地實現
compareTo
方法,這個函數
接收用來計算比較值的一系列回調,按順序依次調用回調方法,兩兩一組分別作比較:
0
這些回調函數能夠像lambda
同樣傳遞,或者像這裏作的同樣,做爲屬性引用傳遞。
處理集合最多見的操做包含兩種:
a[b]
,稱爲 下標運算符。in
運算符。在Kotlin
中,下標運算符是一種約定,使用下標運算符讀取元素會被轉換爲get
運算符方法的調用,而且寫入元素將調用set
,下面咱們爲Point
類添加相似的方法:
get
的參數能夠是任何類型,而不止是
Int
,例如,當你對
map
使用下標運算符時,參數類型是鍵的類型,它能夠是任意類型。還能夠定義具備多個參數的
get
方法,例如若是要實現一個類來表示二維數組或矩陣,你能夠定義一個方法,例如
operator fun get(rowIndex : Int, colIndex : Int)
,而後用
matrix[row, col]
來調用。
下面,咱們再來看一下set
的約定方法:
set
函數後,就能夠在賦值語句中使用下標運算符,
set
的最後一個參數用來接收賦值語句中(等號)右邊的值,其餘參數做爲方括號內的下標。
集合支持的另外一個運算符是in
運算符,用於檢查某個對象是否屬於集合,相應的函數叫作contains
,下面的例子用於判斷某個點是否處於矩形範圍以內:
要建立一個區間時,使用的是..
語法,例如1..10
表明全部從1
到10
的數字,..
運算符是調用rangeTo
函數的一個簡潔方法。rangeTo
返回一個區間,你能夠爲本身的類定義這個運算符,可是,若是該類實現了Comparable
接口,那麼就不須要了,你能夠經過Kotlin
標準庫建立一個任意可比較元素的區間,這個庫定義了能夠用於任何可比較元素的rangeTo
函數
operator fun <T : Comparable<T>> T.rangeTo(that : T) : ClosedRange<T>
複製代碼
這個函數返回一個區間ClosedRanged
,能夠用來檢測其它一些元素是否屬於它。
做爲例子,咱們用LocalData
來構建一個日期的區間:
now..now.plusDays(10)
將會被編譯器轉換爲
now.rangeTo(now.plusDays(10))
,它並非
LocalDate
的成員函數,而是
Comparable
的一個擴展函數。
在for
循環中使用in
運算符表示 執行迭代操做,諸如for(x in list) { }
將被轉換成list.iterator()
的調用,而後在上面重複調用hasNext
和next
方法。
object
來實現匿名內部類的知識。
解構聲明的功能容許你展開單個複合值,並使用它來初始化多個單獨的變量。它再次用到了約定的原理,要在解構聲明中初始化每一個變量,將調用名爲componentN
的函數,其中N
是聲明中變量的位置。
對於數據類,編譯器爲每一個在主構造方法中聲明的屬性生成一個componentN
函數,下面的例子顯示瞭如何手動爲非數據類聲明這些功能:
解構聲明不只能夠用做函數中的頂層語句,還能夠用在其餘能夠聲明變量的地方,例如使用in
循環來枚舉map
中的條目: