Groovy学习笔记3:接口,布尔判断,操作符重载

Groovy接口

Groovy 不需要显示的通过new创建匿名内部类的实例。

//Button对象
class Button {

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

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

}

//按钮的点击监听
interface OnClickListener {
    void onClick()
}
//长按事件监听
interface OnLongClickListener {
    void onLongClick()
}

调用了addOnClickListener方法,同时为该方法提供了一个代码块,借助as操作符,相当于实现了OnClickListener接口:

def button = new Button()

listener = { println 'addListener' }

button.addOnClickListener(listener) as OnClickListener

输出:

addListener

Groovy自会处理剩下的工作。它会拦截对接口中任何方法的调用,然后将调用路由到我们提供的代码块。

对于有多个方法的接口,如果打算为其所有方法提供一个相同的实现,和上面一样,不需要特殊的操作:

def button = new Button()

listener = { println 'addListener' }

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

输出:

addListener
addListener

Groovy没有强制实现接口中的所有方法:可以只定义自己关心的,而不考虑其他方法。如果剩下的方法从来不会被调用,那也就没必要去实现这些方法了。当在单元测试中通过实现接口来模拟某些行为时,这项技术非常有用。

但是在大多数实际情况下,接口中的每个方法需要不同的实现。不用担心,Groovy可以摆平。只需要创建一个映射,以每个方法的名字作为键,以方法对应的代码体作为键值,同时使用简单的Groovy风格,用冒号(:)分隔方法名和代码块即可。

不必实现所有方法,只需实现真正关心的那些即可。如果未予实现的方法从未被调用过,那么也就没有必要浪费精力去实现这些伪存根。当然,如果没提供的方法被调用了,则会出现异常:

class Button {

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

}

//状态监听
interface OnStateChangeListener {

    void onCreate()

    void onStart()

    void onStop()

    void onDestroy()
}

def onStateChangelistener = [
        onCreate: {
            println 'onCreate'
        },
        onStart : {
            println 'onStart'
        },
        onStop  : {
            println 'onStop'
        }  //这里只实现3个状态监听,onDestroy()并未实现
]
button.addOnStateChangeListener(onStateChangelistener as OnStateChangeListener)

结果:

image.png

布尔值判断

Java要求if语句的条件部分必须是一个布尔表达式,比如前面例子中的if(obj!=null)和if(val>0)。

Groovy会尝试推断,如果在需要布尔值的地方放了一个对象引用,Groovy会检查该引用是否为null。它将null视作false,将非null的值视作true:

str = 'hello'

if (str) {
    println str
}

结果:

image.png

更准确的说,表达式的结果还与对象的类型有关。例如,如果对象是一个集合(如java.util.ArrayList),那么Groovy会检查该集合是否为空。
因此,在这种情况下,只有当obj不为null,而且该集合至少包含一个元素时,表达式if(obj)才会被计算为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'

结果:

image.png

集合类不是唯一受到特殊对待的。那么有哪些类型将被特殊对待,Groovy又是如何计算它们的呢?

类型 为真的条件
Boolean true
Collection 集合不为空
character 值不为0
CharSequence 长度不为0
Enumration hasMoreElements()为true
Iterator hasNext()为true
Number Double值部位0
Map 映射不为空
Matcher 至少有一个匹配
Object[] 长度大于0
其他引用类型 引用不为null

除了使用Groovy内建的布尔求值约定,在自己的类中,还可以通过实现asBoolean()方法来编写自己的布尔转换。

操作符重载

Groovy支持操作符重载,可以巧妙地应用这一点来创建DSL

比如我们可以重载++操作符,该示例映射的是String类的next()方法:

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

结果:

a
b
c

Groovy中还可以使用简洁的for-each语法,不过两种实现都用到了String类的next()方法:

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

结果同上,都是输出了abc。

要向集合中添加元素,可以使用<<操作符,该操作符会被转换为Groovy在Collection上添加的leftShift()方法:

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

输出:

[hello, groovy!]

通过添加映射方法,我们可以为自己的类提供操作符,比如为+操作符添加plus()方法:

class B03ComplexNumber {

    def real, imaginary //实部,虚部

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

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

我们执行这段代码:

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

输出:

3 + 7i

ComplexNumber类重载了+操作符。对于计算涉及负数平方根的复杂方程式,复数非常有用: 复数有实部和虚部。
因为在ComplexNumber类上添加了plus()方法,所以可以使用+操作符把两个复数加到一起,得到又一个作为结果的复数。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,594评论 18 139
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,567评论 18 399