概述
十七、特征
特征可以认为是有实现方法的接口,使用trait 关键字声明。特征可以实现接口,使用implement关键字;特征之间可以继承,使用extends关键字。
例子1:声明了一个为水果的特征,有默认的实现(购买方法):
trait Fruit {
void buy() {
println "5元一斤"
}
}
例子2:为食物的一个特征
trait Food {
void eat() {
println "吃面食"
}
}
十八、闭包
1.闭包简单介绍
闭包是一个短的匿名代码块,一个方法甚至可以将代码块作为参数。它们是匿名的。闭包也使用参数和外部变量。
例子1(无参数闭包):
def closer = { println "这是一个闭包" }
例子2(有参数闭包):
def closer2 = { name -> println name }
如果闭包参数只有一个的情况下,参数可以省略,使用闭包中的隐式参数it代替:
def closer3 = { it -> println it }
闭包中参数的类型定义是可选的。如果没有指定参数的类型,那么编译器会自动推断出来。在例子2,如果没有传入参数的话,
那么输出结果就是null。
2.闭包调用
在没有参数的情况下调用闭包:
闭包名称.call()。或者简写成:闭包名称()。如:
def closer = { println "这是一个闭包" }
closer.call() //或者 closer()
如果闭包需要传递参数,则需要在调用的时候给定参数:
def closer = { name -> println name }
closer.call("哈哈哈") //或者 closer("哈哈哈")
3.闭包的返回值
通常情况下,以return关键字声明表示返回值。如果没有return语句,那么闭包的返回值是以闭包内最后一行语句作为返回值的。
def a = { int i -> ++i}
println a(1) //输出结果为 2
def d = {it -> return ++it}
println d(1) //输出结果为 2
4.闭包集合
这个不是闭包内官方的定义,这完全是个人的说法。就是声明一个闭包对象包含了多个闭包而已。它的写法类似写一个Map映射:[ 闭包名称:闭包实现 ],多个闭包使用逗号,分割。
def e = [fun1:{ println "第一"},
fun2:{name -> println "${name}第二"}]
e.fun1()
e.fun2("小明")
5.闭包作为方法参数
在Groovy中,很多用于数据类型(例如列表和集合)的内置方法都有闭包作为参数类型。
def lst = [11, 12, 13, 14];
lst.each {println it}
常规下使用闭包作为参数:
//声明一个方法出来,分别传入一个闭包参数跟一个常规参数。
static void fun1(Closure c, int b) {
println(b + c())
}
//调用形式:
fun1({4}, 4) //输出结果是 8.
当闭包作为参数列表最后一个参数时,可以将闭包移出到参数列表外面显得更加美观:
static void fun3(int a,int b,Closure c) {
println (a+ b+ c())
}
fun3(3,3){
100/2
} //输出结果为56。
当然,闭包作为参数时也不是必须声明 Closure c;直接使用参数名称也是可以的。因为groovy是可以自动转换类型的。
static void fun4(a, int b, c) {
print(a + b - c())
}
fun4(4,4){
return 2
} //输出结果为 6,这里自动识别a为int,c为闭包了
6、委托
委托策略是groovy中闭包独有的语法,这也使得闭包较java的lambda更为高级。在闭包中有3个很重要的属性:
- this:表示闭包的外围类,即最近的外层类,不能是闭包。用getThisObject()获取
- owner:表示闭包的直接外围对象,可以是类也可以是闭包。用 getOwner()获取
- delegate:指定一个第三方类来调用,指定后,这个闭包就属于这个第三方类,可以使用getDelegate()获取
def closer4 = {
println "this= ${this}, ${getThisObject()}"
println "owner= ${owner}, ${getOwner()}"
println "delegate= ${delegate}, ${getDelegate()}"
}
closer4.call()
<!--输出结果:-->
<!--this= test@72c8e7b, test@72c8e7b-->
<!--owner= test@72c8e7b, test@72c8e7b-->
<!--delegate= test@72c8e7b, test@72c8e7b-->
上面执行3的对象结果都是一样的,是因为全写在一个类上里面的。下面修改一下:
class demo {
def c1 = {
println "this= ${this}"
println "owner= ${owner}"
}
void fun1(){
c1()
new demo2().fun2()
}
class demo2 {
def c2 = {
println "this= ${this}"
println "owner= ${owner}"
}
void fun2(){
c2()
}
}
}
def demo = new demo()
demo.fun1()
/*
输出结果:
this= demo@55de24cc
owner= demo@55de24cc
this= demo$demo2@7e990ed7
owner= demo$demo2@7e990ed7
*/
这里2次的输出结果是不一样的。第一次的this,owner指向demo对象;第二次则是指向demo2的对象。this,owner都是指向最近类(owner可以是闭包)的,而delegate则是由第三方类使用,需要手动指定。
7、delegate策略
先搞清楚这个策略的概念:在闭包中,属性没有指明其所有者的时候,delegate策略就会发挥作用。以下是delegate的几种策略机制:
- Closure.DELEGATE_FIRST:优先从delegate中寻找属性或方法,找不到再从owner中寻找;
- Closure.DELEGATE_ONLY:只在delegate中寻找;
- Closure.OWNER_FIRST: 这是默认的策略,优先从owner中寻找属性或方法,找不到再从delegate中寻找;
- Closure.OWNER_ONLY:只在owner寻找;
- Closure.TO_SELF:在闭包里面寻找;
举例子:
class A {
private String color
private String weight
private String size
A(String color = "", String weight = "", String size = "150cm") {
this.color = color
this.weight = weight
this.size = size
}
def fun0 = {
println "A:外围类:${getThisObject()}"
println "A:this= ${this}"
println "A:owner= ${owner}"
println "A:delegate= ${delegate}"
}
def fun1 = {
println "$color, $weight"
}
def fun2 = {
println size
}
}
A newA = new A("红色", "100")
newA.fun2()
def c1 = {
println size
}
c1()
声明了一个内部类A,有3条属性以及若干个闭包。类外部有一个闭包c1,只是输出了size。分别执行内部类A的fun2与外部闭包c1。结果是类A输出了150cm。
而c1()却抛出异常了:Caught: groovy.lang.MissingPropertyException: No such property: size for class: test
。很明显,它说test类没有size这个属性。首先c1闭包中的size并没有指定所有者,会触发delegate策略,先在它的owner中(test类)寻找,没有找到后,发现也没有使用委托。于是抛出异常。修改代码:
c1.delegate = newA
c1()
将c1委托给A的示例后,执行c1,程序没有抛出异常并且输出结果为: 150cm。再修改代码,手动设置委托策略:
c1.resolveStrategy = Closure.OWNER_ONLY
c1.delegate = newA
c1()
此时委托策略只能从owner中寻找。结果抛出异常:Caught: groovy.lang.MissingPropertyException: No such property: size for class: test
,再看个例子,
添加一个类B:
class B {
private String color
private String weight
B(String color = "", String weight = "") {
this.color = color
this.weight = weight
}
def fun1 = {
println "$color, $weight"
}
}
B newB = new B("绿色","200")
newA.fun1.delegate = newB
newA.fun1()
实例化另一个内部类B对象 newB,并且将类A中的闭包fun1委托给B对象。结果却是:A中的属性:红色, 100 。可能会有疑问:fun1委托给了B对象,但是类B中也有color跟weight属性,为什么输出的确实A累中的color跟weight?这里还是委托策略的原因。fun1确实是委托给了B的实例。但是使用的还是默认下的策略:优先从owner中寻找属性或方法,找不到再从delegate中寻找。fun2的owner自然是类A,A中拥有size属性,就不会再往委托下去找了,而是输出结果。OK,修改fun1的委托策略:
newA.fun1.resolveStrategy = Closure.DELEGATE_FIRST
输出结果为:绿色, 200。好了这会是B类中的color与weight了。使用的是A类fun1,使用了委托后,结果确实B类的属性,这就是委托策略的用处。
最后
以上就是阳光金针菇为你收集整理的Groovy基础知识二的全部内容,希望文章能够帮你解决Groovy基础知识二所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复