Groovy學(xué)習(xí)筆記3:接口,布爾判斷,操作符重載

Groovy接口

Groovy 不需要顯示的通過(guò)new創(chuàng)建匿名內(nèi)部類的實(shí)例。

//Button對(duì)象
class Button {

    void addOnClickListener(OnClickListener listener) {
        listener.onClick()
    }

    void addOnLongClickListener(OnLongClickListener listener) {
        listener.onLongClick()
    }

}

//按鈕的點(diǎn)擊監(jiān)聽
interface OnClickListener {
    void onClick()
}
//長(zhǎng)按事件監(jiān)聽
interface OnLongClickListener {
    void onLongClick()
}

調(diào)用了addOnClickListener方法,同時(shí)為該方法提供了一個(gè)代碼塊,借助as操作符,相當(dāng)于實(shí)現(xiàn)了OnClickListener接口:

def button = new Button()

listener = { println 'addListener' }

button.addOnClickListener(listener) as OnClickListener

輸出:

addListener

Groovy自會(huì)處理剩下的工作。它會(huì)攔截對(duì)接口中任何方法的調(diào)用,然后將調(diào)用路由到我們提供的代碼塊。

對(duì)于有多個(gè)方法的接口,如果打算為其所有方法提供一個(gè)相同的實(shí)現(xiàn),和上面一樣,不需要特殊的操作:

def button = new Button()

listener = { println 'addListener' }

button.addOnClickListener(listener) as OnClickListener
button.addOnLongClickListener(listener) as OnLongClickListener

輸出:

addListener
addListener

Groovy沒(méi)有強(qiáng)制實(shí)現(xiàn)接口中的所有方法:可以只定義自己關(guān)心的,而不考慮其他方法。如果剩下的方法從來(lái)不會(huì)被調(diào)用,那也就沒(méi)必要去實(shí)現(xiàn)這些方法了。當(dāng)在單元測(cè)試中通過(guò)實(shí)現(xiàn)接口來(lái)模擬某些行為時(shí),這項(xiàng)技術(shù)非常有用。

但是在大多數(shù)實(shí)際情況下,接口中的每個(gè)方法需要不同的實(shí)現(xiàn)。不用擔(dān)心,Groovy可以擺平。只需要?jiǎng)?chuàng)建一個(gè)映射,以每個(gè)方法的名字作為鍵,以方法對(duì)應(yīng)的代碼體作為鍵值,同時(shí)使用簡(jiǎn)單的Groovy風(fēng)格,用冒號(hào)(:)分隔方法名和代碼塊即可。

不必實(shí)現(xiàn)所有方法,只需實(shí)現(xiàn)真正關(guān)心的那些即可。如果未予實(shí)現(xiàn)的方法從未被調(diào)用過(guò),那么也就沒(méi)有必要浪費(fèi)精力去實(shí)現(xiàn)這些偽存根。當(dāng)然,如果沒(méi)提供的方法被調(diào)用了,則會(huì)出現(xiàn)異常:

class Button {

    void addOnStateChangeListener(OnStateChangeListener listener) {
        listener.onCreate()
        listener.onStart()
        listener.onStop()
        listener.onDestory()
    }

}

//狀態(tài)監(jiān)聽
interface OnStateChangeListener {

    void onCreate()

    void onStart()

    void onStop()

    void onDestroy()
}

def onStateChangelistener = [
        onCreate: {
            println 'onCreate'
        },
        onStart : {
            println 'onStart'
        },
        onStop  : {
            println 'onStop'
        }  //這里只實(shí)現(xiàn)3個(gè)狀態(tài)監(jiān)聽,onDestroy()并未實(shí)現(xiàn)
]
button.addOnStateChangeListener(onStateChangelistener as OnStateChangeListener)

結(jié)果:

image.png

布爾值判斷

Java要求if語(yǔ)句的條件部分必須是一個(gè)布爾表達(dá)式,比如前面例子中的if(obj!=null)和if(val>0)。

Groovy會(huì)嘗試推斷,如果在需要布爾值的地方放了一個(gè)對(duì)象引用,Groovy會(huì)檢查該引用是否為null。它將null視作false,將非null的值視作true:

str = 'hello'

if (str) {
    println str
}

結(jié)果:

image.png

更準(zhǔn)確的說(shuō),表達(dá)式的結(jié)果還與對(duì)象的類型有關(guān)。例如,如果對(duì)象是一個(gè)集合(如java.util.ArrayList),那么Groovy會(huì)檢查該集合是否為空。
因此,在這種情況下,只有當(dāng)obj不為null,而且該集合至少包含一個(gè)元素時(shí),表達(dá)式if(obj)才會(huì)被計(jì)算為true:

str1 = null
println str1 ? 'str1 is not null' : 'str1 is null'

str2 = [1, 2, 3]
println str2 ? 'str2 is not null' : 'str2 is null'

str3 = []
println str3 ? 'str3 is not null' : 'str3 is null'

結(jié)果:

image.png

集合類不是唯一受到特殊對(duì)待的。那么有哪些類型將被特殊對(duì)待,Groovy又是如何計(jì)算它們的呢?

類型 為真的條件
Boolean true
Collection 集合不為空
character 值不為0
CharSequence 長(zhǎng)度不為0
Enumration hasMoreElements()為true
Iterator hasNext()為true
Number Double值部位0
Map 映射不為空
Matcher 至少有一個(gè)匹配
Object[] 長(zhǎng)度大于0
其他引用類型 引用不為null

除了使用Groovy內(nèi)建的布爾求值約定,在自己的類中,還可以通過(guò)實(shí)現(xiàn)asBoolean()方法來(lái)編寫自己的布爾轉(zhuǎn)換。

操作符重載

Groovy支持操作符重載,可以巧妙地應(yīng)用這一點(diǎn)來(lái)創(chuàng)建DSL

比如我們可以重載++操作符,該示例映射的是String類的next()方法:

for (ch = 'a'; ch < 'd'; ch++) {
    println ch
}

結(jié)果:

a
b
c

Groovy中還可以使用簡(jiǎn)潔的for-each語(yǔ)法,不過(guò)兩種實(shí)現(xiàn)都用到了String類的next()方法:

for (ch in 'a'..'c') {
    println ch
}

結(jié)果同上,都是輸出了abc。

要向集合中添加元素,可以使用<<操作符,該操作符會(huì)被轉(zhuǎn)換為Groovy在Collection上添加的leftShift()方法:

list = ['hello']
list << 'groovy!'
println list

輸出:

[hello, groovy!]

通過(guò)添加映射方法,我們可以為自己的類提供操作符,比如為+操作符添加plus()方法:

class B03ComplexNumber {

    def real, imaginary //實(shí)部,虛部

    def plus(other) {
        new B03ComplexNumber(real: real + other.real,
                imaginary: imaginary + other.imaginary)
    }

    @Override
    String toString() {
        return "$real ${imaginary > 0 ? '+' : ''} ${imaginary}i "
    }
}

我們執(zhí)行這段代碼:

c1 = new B03ComplexNumber(real: 1, imaginary: 4)
c2 = new B03ComplexNumber(real: 2, imaginary: 3)
println c1 + c2

輸出:

3 + 7i

ComplexNumber類重載了+操作符。對(duì)于計(jì)算涉及負(fù)數(shù)平方根的復(fù)雜方程式,復(fù)數(shù)非常有用: 復(fù)數(shù)有實(shí)部和虛部。
因?yàn)樵贑omplexNumber類上添加了plus()方法,所以可以使用+操作符把兩個(gè)復(fù)數(shù)加到一起,得到又一個(gè)作為結(jié)果的復(fù)數(shù)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,697評(píng)論 19 139
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類相關(guān)的語(yǔ)法,內(nèi)部類的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚_t_閱讀 34,853評(píng)論 18 399

友情鏈接更多精彩內(nèi)容