一 闭包
自己在'Python'、'Lua'、'Go'、'Perl'中都'遇到过闭包',后续对比差异
核心: 'Lua'和'Groovy'中闭包是一个核心点
疑惑: groovy为什么要闭包?闭包的'优势'?-->仅仅是能够'访问闭包外'的属性和方法吗?
各种语言里面闭包的定义
百度百科
编程语言中的闭包
(1)定义
书面解释: 闭包是可以用作'函数参数'和'方法参数'的'代码块'
官方理解: Groovy中的闭包是一个'开放、匿名'的'代码块,'可以'接受'参数、返回值
通俗理解: Groovy的闭包更象是一个"代码块"或者"方法指针",代码在某处'被定义'然后在其后的'调用处'执行
更通俗: 闭包在groovy中是一个'处于代码上下文'中的开放的、匿名代码块,它可以'访问'到其'外部'的变量或方法
(2)粗略理解
Groovy的优点和缺点
二 闭包的实践
(1)原理理解
1)闭包就是一段可以'使用参数'的'代码片段'
2)每个'闭包'会被编译成'继承'groovy.lang.Closure 类的类-->具体查看'编译后的.class文件'
3)最后groovy编译器都会把编译成对'doCall()方法'的调用,这是groovy对闭包的一个隐藏方法,通过该方法可以'传递参数'并'调用这个闭包'
(1)创建闭包
① 无参数的闭包
++++++'变量作用域问题'++++++
1)闭包获'取了闭包外'str的值
备注:方法是不能'访问外部def' 定义的变量
2)当变量值发生变化,闭包里面变量的值'同样发生变化'
② 带参数的闭包-->'不给默认值'
备注: 多个参数,以'逗号隔开'即可
③ 带参数的闭包-->设置默认值
④ Groovy几个常用的闭包
说明: 闭包一定是'有返回值'的,这就是闭包'有别于方法'的一点,方法是可以'没有返回值'的
三 闭包的一个内置变量
① it
说明: 目前先学习'隐式'变量-->'it'
效果: 如果没有在'闭包块'中定义变量,来接收'传入参数',默认用'it'来接收
说明: 调用是如果'没有传'参数,it为'null'
源码分析 upto 方法是如何使用闭包的
说明: 没有学过'Java面向对象'的知识,可以跳过'②、③、④'部分,后续进行讲解
四 闭包的三个内置对象
① this owner delegate
++++++++++++++++'内置对象的特点'++++++++++++++++
1)this : 跟Java一样,是定义'闭包所在类'的一个引用,不管有'多少层闭包'嵌套,this指向的都是最上层的类
细节: 如果是'内部类'的闭包,则指向内部类
通俗: 闭包中的this就是'定义闭包的类对象'
2)owner : 封闭闭包的对象(如果只有一层闭包就是this,如果有'多层闭包嵌套'就是含有此闭包的'上层'闭包)
通俗理解: 定义闭包的'直接外围对象'-->除了类,闭包也是'对象'
3)delegate : 缺省值是owner,但是'可以改变'
细节: 它的'主要作用'是让你在定义闭包时'访问一些你不拥有'的变量
+++++++++++this、owner、delegate'指向总结'+++++++++++
1)this 永远是指定义'该闭包类';如果存在'内部类',则是'最内层'的类,但this'不是指当前闭包'对象
2)owenr 永远是指定义该闭包'最近的类'或者该'owner'所在闭包的'上一级闭包'对象
说明: 类似'javascript' 的原型,向上'查找最近'的
备注: 闭包只能定义在'类中'或者'闭包中'
+++++++++++闭包的 'owner' 与闭包中的 'this'区别+++++++++++
细微的区别:owner 将返回'直接封闭对象',可能是是'闭包'也可能是'类';而'this'返回的永远是'类'
代理是 groovy 闭包的关键,为 groovy '成 SDL 语言'提供基础
demo案例
1)只有一个类
说明: 在闭包中'定义'闭包
结构: 一个类中定义'闭包1',在'闭包1'内定义'闭包2',在'闭包2'定义'闭包3'
package wzj.com.groovy
class Class1 {
def closure = {
println "=====================分割线1====================="
// this : 跟Java一样,是定义闭包所在类的一个引用;不管有多少层闭包嵌套,this指向的都是'最上层的类'
println "this = " + this.class.name
// owner : 封闭闭包的对象(如果只有一层闭包就是this;如果有'多层闭包'嵌套就是含有此闭包的'上层闭包')
println "owner = " + owner.class.name
// delegate :缺省值是owner
println "delegate = " + delegate.class.name
def nestedClos = {
println "=====================分割线2====================="
println "this = " + this.class.name
println "owner = " + owner.class.name
println "delegate = " + delegate.class.name
def thirdClos = {
println "=====================分割线3====================="
println "this = " + this.class.name
println "owner = " + owner.class.name
println "delegate = " + delegate.class.name
}
thirdClos()
}
nestedClos()
}
}
++++++++++++++'解读'++++++++++++++
1)只有一个类('没有内部类'),则'this'始终是该类本身-->'Class1'
2)只有一个类('没有内部类'),则'owner'是'owner当前所在闭包'的'上一级'闭包
效果1: nestedClos闭包内所在的'owner'是上一级闭包'closure' -->也即Class$_closure1
效果2: thirdClos闭包所在的'owner'是上一级闭包'nestedClos' -->也即Class$_closure1$_closure2
2)定义内部类
++++++++++++++'闭包结构说明'++++++++++++++
1)内部类'InnerClass'中定义闭包-->'outerClosure'
2)在内部类定义的闭包'outerClosure'内再定义闭包'innerClosure'
package wzj.com.groovy.closure
class OuterClass {
// 说明: 在OuterClass定义一个'内部类'InnerClass
class InnerClass {
// 说明:在'内部类'InnerClass中定义了一个'outerClosure闭包'
def outerClosure = {
// 说明:在outerClosure'闭包中'定义了一个'innerClosure闭包'
def innerClosure = {
}
// 4)打印innerClosure闭包对应的this,owner,delegate对象和innerClosure对象的'toString方法'
printfMsg("innerClosure", innerClosure)
println("------")
// 5)打印outerClosure闭包对应的this,owner,delegate对象和outerClosure对象的'toString方法'
printfMsg("outerClosure", outerClosure)
}
void printfMsg(String flag, Closure closure) {
// 在闭包内部,有三个内置对象this、owner、delegate,我们可以直接this、owner、delegate调用
// 1、getThisObject() 等于 'this'
def thisObject = closure.getThisObject()
// 2、getOwner() 等于 'owner'
def ownerObject = closure.getOwner()
// 3、getDelegate() 等于 'delegate'
def delegate = closure.getDelegate()
println("${flag} this: ${thisObject.toString()}")
println("${flag} owner: ${ownerObject.toString()}")
println("${flag} delegate: ${delegate.toString()}")
}
}
def callInnerMethod() {
// 2)调用内部类
def innerClass = new InnerClass()
// 3)调用内部类的'outerClosure闭包'
innerClass.outerClosure.call()
println("------")
println("outerClosure toString ${innerClass.outerClosure.toString()}")
}
static void main(String[] args) {
// 1)main入口
new OuterClass().callInnerMethod()
}
}
说明: 省略'@'之后的字符理解即可
+++++++++++++++'inner'Closure+++++++++++++++
1)this:结果是OuterClass$InnerClass对象
2)owner:结果是OuterClass$InnerClass$_closure1对象,即'outerClosure'
3)delegate:同owenr
+++++++++++++++'outer'Closure+++++++++++++++
1)this:结果是OuterClass$InnerClass对象
2)owner:结果是OuterClass$InnerClass对象
3)delegate:同owenr
② 重点讲解 delegate
闭包可以'设置'delegate对象,设置delegate的'意义'-->就是将'闭包'和一个'具体的对象'关联起来
delegate'委托'是一种常用'设计模式'
需求:闭包里'修改'Person类的'name'和'age',还想'调用eat方法',如何关联?
1)定义Groovy类
package wzj.com.groovy.closure
// Person.groovy
class Person {
def name
def age
def eat(String food) {
println("你喂的${food}真难吃")
}
// 重写(Override)重写是子类对父类的允许访问的方法的实现过程进行重新编写,返回值和形参都'不能改变'
@Override
String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}'
}
}
2)Groovy测试
package wzj.com.groovy.closure
class Main {
def cc = {
name = "刘徳化"
age = 30
// 调用eat方法
eat "油条"
}
static void main(String... args) {
Main main = new Main()
Person person = new Person(name: "wzj", age: 18)
println person.toString()
// 1、修改之前:cc闭包的delegate是'Main对象'
// 2、修改之后:cc闭包的delegate是'Person对象'
main.cc.delegate = person
// 2)调用cc闭包-->修改了name和age属性
main.cc.call()
// 3)打印修改后的
println person.toString()
}
}
3)测试结果
结果: 在'闭包中'可以访问'被代理对象'的属性和方法
++++++++++++++++delegate'解决'闭包内的'属性的访问'或'方法的调用'++++++++++++++++
疑问:如果'闭包所在的类'或'闭包中和被代理的类'中有'相同'名称的方法,到底要调用哪个方法,groovy考虑到了这个问题,为我们设定了'几个代理的策略':
也即: 闭包拥有的'不同的delegate策略'如下:
在闭包中,当一个'属性'或者'方法'没有'指明其所有者'的时候,delegate策略就会发挥作用了
例如: 上面的'name'、'age'属性,以及'eat'方法
// 修改策略方式
// main.cc.setResolveStrategy(Closure.DELEGATE_FIRST)
// main.cc.setResolveStrategy(Closure.OWNER_FIRST)
delegate策略
其它参考
③ 继续讲解一个案例
//delegate委托的用法
class Dog{
def play = {
"wang wang!"
}
def childmind = {
println delegate.play();
}
}
class Cat {
def play = {"mi mi !"}
}
def dog = new Dog()
def cat = new Cat()
// 1)修改delegate之前
dog.childmind()
// 2)修改delegate之后的
dog.childmind.delegate = cat;
dog.childmind()
// 上面的例子是狗爸爸让老猫帮忙照看他的狗儿子玩游戏。
后续: 辩证Java8的'Lambda表达式'、'匿名内部类'、'闭包'关系
从Java到Groovy的八级进化论
搞定Groovy闭包这一篇就够了