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é)果:

布爾值判斷
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é)果:

更準(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é)果:

集合類不是唯一受到特殊對(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ù)。