`
klcwt
  • 浏览: 195950 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

Groovy探索之delegate关键字(全)

阅读更多
Groovy探索之delegate关键字 一(2)
from: http://blog.csdn.net/hivon/archive/2008/10/27/3156043.aspx

delegate*关键字在Groovy语言中应用广泛,大体可以分为两个地方的使用,即在方法中使用和在闭包中使用。本系列计划用两个篇幅来谈谈*
delegate*关键字的使用,本篇说说*delegate*关键字在闭包中的使用,下一个篇幅主要说说它在方法中的使用。


在Groovy语言的官方文档上,在谈到闭包的部分的时候,是这样描述this、owner和*delegate*这三个关键字的。


this: 跟Java一样,this指的是定义闭包的封装类。


owner: 封装对象(this或者环绕闭包)


*delegate*:默认情况下和owner一样,但是可以改变。


上面的描述虽然很清楚,但也不够详细。我们首先来举出一个例子来理解一下上面的描述:


class Testor1 {
    def num = 1
    def add12 = {
           this.num++
    }


    def add13 = {
           owner.num++
    }


    def add14 = {
           *delegate*.num++
    }


  static void main(args) {
       def t = new Testor1()
       t.add12()
       println t.num
       t.add13()
       println t.num
       t.add14()
       println t.num
  }



}


运行结果为:

2


3


4


可以看到,上面的this、owner和*delegate*都指向了Testor1类的实例,果然跟官方文档描述的一样。


从上面的描述和例子可以看到,this关键字基本上很单纯,和Java语言的this用法基本一致;而owner关键字和*delegate*
关键字的指向都是相同的,但*delegate*关键字的指向可以改变,因此更加的灵活。所以,基于上面的分析,我们下面的篇幅重点来谈谈*delegate*­关键字及其相关的作用和用法,而对于this关键字和owner关键字,则不再涉及。


前面说过,Groovy语言的官方文档对于上面三个关键字的描述虽然很清楚,但是不够详细。为什么这样说呢,因为闭包的情况也比较复杂,上面简简单单的三句话并­不能概括所有的情况。下面试着使用
*delegate*关键字来举出几个例子来说明这种复杂的情况。


class Testor3 {
    int num = 1
    def add = {
           *delegate*.num++
    }
  static void main(args) {
       def t = new Testor3()


       t.add()
       println t.num
  }



}


这个例子的运行结果为:

2


和官方文档的描述是一致的。下面我们再来看一个例子:


class Testor4 {
    int num = 1
    def static add = {
       *delegate*.num++
    }
  static void main(args) {
       Testor4.add()
  }



}


运行的结果就报了"No such
property"的错误。为什么会这样呢?其实原因很简单,就是因为闭包是静态的,它的"*delegate*.num++"语句中的"num"变量也只能引­用静态变量,而我们的"Testor4"类中没有一个静态的"num"变量,当然会报"No
such property"的错误。如果我们把上面的"Testor4"类稍稍改变,变成下面的样子:

class Testor4 {
    static int num = 1
    def static add = {
       *delegate*.num++
    }
  static void main(args) {
       Testor4.add()
       println Testor4.num
  }



}


则运行结果为:

2


明白了上面的道理,下面的一些问题就可以迎刃而解。


一个类中的闭包中的变量也可以没有三个关键字"this"、"owner"和"*delegate*",请看下面的示例(例1):


class Testor1 {
    def num = 1
    def add11 = {
           def num =2
           num++
    }
  static void main(args) {
       def t = new Testor1()
       t.add11()
       println t.num
  }



}


运行结果为:

1


如果我们把上面代码的闭包中的"def num =2"去掉,变成下面的样子(例2):


class Testor1 {
    def num = 1
    def add11 = {
           num++
    }
  static void main(args) {
       def t = new Testor1()
       t.add11()
       println t.num
  }



}


则结果为:

2


从上面的测试结果可以看出,定义在一个类中的闭包,如果它引用的变量没有任何修饰,则这个变量首先指向闭包中定义的变量,如上面的"例1"中,在
闭包里定义了"def num =2",所以接着的语句"num++"中的变量"num"指向了闭包定义的"num",最后"println
t.num"的结果就只能是1了。如果这个变量在闭包中没有定义,如"例2",那么该变量就相当于加了"*delegate*
"关键字修改的变量。所以语句"num++"就相当于"语句"*delegate*.num++",最后"println
t.num"的结果就是2了。如果在类中也没有定义该变量,那么上面的代码运行就会报"No such property"的错误了。


既然在闭包中,不加任何关键字修饰的变量在闭包找不到local变量定义时,它相当于加了"*delegate*"关键字的变量。那么任何"*delegate­*"关键字给变量所带来的情况也同样发生在不加任何关键字修饰的变量上。如上面所谈到的静态闭包或者关闭定义在静态方法中给变量带来的问题。下面试着举一例:


class Testor5 {
    static int num = 1
    static def add = {
       num++
    }


  static void main(args) {
       Testor5.add()
       println Testor5.num
  }



}


当然了,如你所想,上面代码的运行结果为:

2


到此为止,我们通过一些简单的例子,明白了"*delegate*
"关键字的基本用法。从来都是基本用法简单,但是在实际使用中却千变万化,从基本用法转化到实际使用需要一个艰难的过程。下面,我们就通过一个比较实际的例子,­却出神入化的使用到了"
*delegate*"关键字的各种用法,希望通过对这个例子的学习,我们可以从掌握"*delegate*"关键字的基础知识转化到实际使用状态。



这个例子首先要从一个GroovyBean说起:
class Person
{
    String name


}


这是一个很简单的GroovyBean类,下面,我们为这个GroovyBean类做了一个Builder类,如下:

class PersonBuilder {
    def persons = []
    def persons(Closure closure)
    {
       closure.delegate = this
       closure()
       return this.persons
    }
    def getProperty(String propertyName)
    {
       this.persons<<new Person(name:"${propertyName}")
    }



}


先不要看这个builder类,我们先来看看如何使用这个builder类,我们在“PersonBuilder”类里加入如下的一个“main”方法:

  static void main(args) {
      def pers = new PersonBuilder().persons{
         mike
         alice
         tom
         mark
      }
      pers.each{
         println it.name
      }
  }


这个“main”方法的运行结果为:


mike


alice


tom


mark


正是这个很简单的功能,却完完整整的为我们演示了“delegate”关键字的功能。我们首先来看“main”方法。


我们为“PersonBuilder”类的“persons”方法传入了如下的一个闭包:


{
         mike
         alice
         tom
         mark
  }


下面,我们来看“PersonBuilder”类的“persons”方法:


def persons(Closure closure)
    {
       closure.delegate = this
       closure()
       return this.persons



}


我们先不管第一个语句行:“closure.delegate = this”,来看第二个语句行:

closure()


即执行传入的闭包。那么闭包里有些什么语句呢?很简单,就是执行四个变量:


mike
alice
tom
mark


值得注意的是,这个四个变量没有任何关键字来修饰,前面我们说过,如果闭包里的变量没有任何关键字来修饰,那么首先看闭包里有没有把该变量定义成local变量­,我们可以再看看传入的闭包,没有在闭包的任何地方把它们四个变量定义成local变量。所以这个四个语句行就相当于下面的四个语句行:


delegete.mike
delegete.alice
delegete.tom
delegete.mark


学过Gpath的人都知道,在Groovy语言中,“delegete.mike”相当于如下的调用如下的语句:
delegate.getMike()


另外的三个语句如此类推。这就意味着我们希望在“PersonBuilder”类中有“getMike”这类的方法。我们再看看“PersonBuilder”­类,虽然没有显式的“getMike”这类的方法,但是有一个“getProperty”方法。我们知道,在Groovy语言中,“getProperty”方­法会分派所有的“get”方法,不管是“getMike”还是“getAlice”,都会调用“getProperty”方法。


所以,通过以上的分析,我们闭包的四个语句都会调用“getProperty”方法。而“getProperty”方法干了些什么事呢?


this.persons<<new Person(name:"${propertyName}")


看看上面的语句,很简单,就是以闭包里的变量名作为参数,来实例化一个Person类对象,然后把这个对象add到一个名为“persons”的List对象里­存起来。


到目前为止,我们已经分析了“PersonBuilder”类的工作原理,但却漏掉了一个最重要的要点,没有它,这个“PersonBuilder”类的构思再­好,也是实现不了的。那么这个要点是什么呢?


我们在谈“PersonBuilder”类的“persons”方法的时候,放下了第一个语句行:


closure.delegate = this


那么,这个语句行有什么用呢?


我们还是可以先做一个测试,将这个语句行从“PersonBuilder”类中注销掉,那么,“PersonBuilder”类就变成了下面的样子:


class PersonBuilder {
    def persons = []
    def persons(Closure closure)
    {
       //closure.delegate = this
       closure()
       return this.persons
    }
    def getProperty(String propertyName)
    {
       this.persons<<new Person(name:"${propertyName}")
    }
  static void main(args) {
      def pers = new PersonBuilder().persons{
         mike
         alice
         tom
         mark
      }


      pers.each{
         println it.name
      }
  }



}


现在,我们运行上面的“main”方法,结果如下:

Exception in thread "main" groovy.lang.MissingPropertyException: No such property: mike for class: PersonBuilder


at groovy.lang.MetaClassImpl.invokeStaticMissingProperty(MetaClassImpl.java:73­0)


这个Exception很长,我只截取了前面两句话。为什么会抛出“No such property”的错误呢?


我们再来看看“main”方法,发现闭包:


{
         mike
         alice
         tom
         mark
  }


是定义在“main”方法里的,而“main”方法是一个静态方法,而我们前面说过,像“mike”这样的语句相当于“delegete.mike”。基于这个­一个原因,“delegete.mike”中的“delegate”肯定指向“PersonBuilder”类,而“delegete.mike”语句肯定会调­用“PersonBuilder”类的静态的“getMike”方法。


而上面的“PersonBuilder”类中没有静态的“getMike”这类的方法,当然就会报“No such property”的错误了。


基于这样的分析,如果我们在上面的“PersonBuilder”类加入如下的静态方法:


    def static getMike()
    {
       this.persons<<new Person(name:"mike")



}


那么,是不是在执行闭包里的“mike”语句行时,就不会报错了呢?

我们把“getMike()”方法加入到“PersonBuilder”类中,然后,再将“persons”变量也变成静态变量。如下所示:


class PersonBuilder {
    def static persons = []
    def persons(Closure closure)
    {
       //closure.delegate = this
       closure()
       return persons
    }


    def getProperty(String propertyName)
    {
       persons<<new Person(name:"${propertyName}")
    }


    def static getMike()
    {
       persons<<new Person(name:"mike")
    }
  static void main(args) {


      def pers = new PersonBuilder().persons{
         mike
          alice
         tom
         mark
      }
      pers.each{
         println it.name
      }
  }



}


执行,结果为:

Exception in thread "main" groovy.lang.MissingPropertyException: No such property: alice for class: delegateBuilder.PersonBuilder


at groovy.lang.MetaClassImpl.invokeStaticMissingProperty(MetaClassImpl.java:73­0)


可以看到,“No such property”的错误是报在“alice”变量的上面。这说明,“mike”可以正常的执行了。


现在,我们就基本上可以猜测“closure.delegate = this”语句行的作用了。由于闭包“closure”是定义在静态方法中,我们当然希望它定义在非静态方法中,而闭包的“delegate”变量又刚好是可以­改变的。


所以,我们通过“closure.delegate = this”语句行来改变闭包的“delegate”变量的指向,将它指向“this”,而刚好“this”又是指向当前对象的。这就使得闭包定义在一个非静态方­法里。就使得闭包中的语句行可以使用“getProperty”方法了。而我们的“PersonBuilder”类达到了我们要想的目的。


可以说,这个例子是一个很好的使用了闭包关键字“delegate”的例子。虽然我们不会在实际中使用这个例子,但它给我们的启示依然是很重要的。我们很好的理­解了这个例子,才可以在实际的编程中灵活的使用闭包的“delegate”关键字。


From: Alex wang
Sent: Friday, November 14, 2008 9:09 PM
To: grailsunion@googlegroups.com
Subject: [grailsunion:73] [转]Groovy探索之delegate关键字


原文是 这里: http://www.java2000.net/p11260 ,不过我打开这个连接firefox会死,是通过google快照查看的。


===========================================================================­=============
delegate关键字在Groovy语言中应用广泛,大体可以分为两个地方的使用,即在方法中使用和在闭包中使用。本系列计划用两个篇幅来谈谈delegat­e关键字的使用,本篇说说delegate关键字在闭包中的使用,下一个篇幅主要说说它在方法中的使用。


在Groovy语言的官方文档上,在谈到闭包的部分的时候,是这样描述this、owner和delegate这三个关键字的。


this: 跟Java一样,this指的是定义闭包的封装类。


owner: 封装对象(this或者环绕闭包)


delegate:默认情况下和owner一样,但是可以改变。


上面的描述虽然很清楚,但也不够详细。我们首先来举出一个例子来理解一下上面的描述:


class Testor1 {
    def num = 1
    def add12 = {
           this.num++
    }


    def add13 = {
           owner.num++
    }


    def add14 = {
           delegate.num++
    }


  static void main(args) {
       def t = new Testor1()
       t.add12()
       println t.num
       t.add13()
       println t.num
       t.add14()
       println t.num
  }



}


运行结果为:

2


3


4


可以看到,上面的this、owner和delegate都指向了Testor1类的实例,果然跟官方文档描述的一样。
...

分享到:
评论

相关推荐

    Groovy语法系列教程之关键字和标识符(二).pdf

    接下来,我们将详细探讨Groovy编程语言中的关键字和标识符。 在Groovy中,关键字是指在语言中具有特殊意义的保留字,它们被用于表达语言的语法结构和控制流程,不可以被用作普通的标识符。比如,我们不能创建一个名...

    groovy入门经典,groovyeclipse 插件

    Groovy也支持使用`def`关键字来定义未指定类型的变量。 闭包是Groovy的一个核心特性,它类似于函数指针,可以被用作参数传递或者作为返回值。闭包在Groovy中的定义形式通常为`{参数列表 -&gt; 代码块}`。闭包的this...

    apache-groovy-3.0.8.zip apache官网的groovy3.0.8版本

    apache-groovy-3.0.8.zip apache官网的groovy3.0.8版本,希望大家多多下载,apache-groovy-3.0.8.zip apache官网的groovy3.0.8版本,希望大家多多下载,apache-groovy-3.0.8.zip apache官网的groovy3.0.8版本,希望...

    Groovy Script 入门

    ### Groovy Script 入门知识点详解 #### 一、Groovy脚本简介 Groovy是一种灵活的面向对象的编程语言,它运行在Java平台上。由于其语法简洁且与Java高度兼容,因此对于Java开发者来说非常容易上手。Groovy不仅支持...

    Java调用Groovy,实时动态加载数据库groovy脚本

    1. 引入Groovy库:在Java项目中添加Groovy的相关依赖,通常是`groovy-all`,确保Java能够访问Groovy运行时环境。 2. 创建GroovyClassLoader:使用这个类加载器可以动态加载和执行Groovy脚本。它继承自Java的...

    Groovy入门教程.doc

    Groovy允许省略变量的类型声明,使用`def`关键字即可。在`main`方法中,可以使用`println`打印"Hello World"。如果整个文件只有一句`println`语句,Groovy依然能正确执行。 Groovy的语法特点包括: 1. **类型推断**...

    groovy-sdk-4.0.3

    Groovy SDK 4.0.3 是一个针对Groovy编程语言的软件开发工具包,它包含了Groovy语言的运行环境和开发所需的各种组件。...通过安装和配置这个SDK,你可以开始探索Groovy的动态世界,体验它在各种应用场景中的强大功能。

    Groovy插件

    在Marketplace的搜索框内,输入“Groovy”关键字,系统会列出所有与Groovy相关的插件。找到名为“Groovy-Eclipse”的插件,它是官方推荐的Groovy开发工具集。 如果没有在Marketplace中找到Groovy插件,或者由于网络...

    groovy-2.3.6-installer

    Groovy是一种动态、开源的编程语言,它是Java平台上的一个JVM(Java Virtual Machine)语言。Groovy结合了Python、Ruby和Perl等脚本语言的简洁性和灵活性,并且完全兼容Java,可以无缝地与Java代码集成。在"groovy-...

    groovy 经典入门 通俗易懂

    以上内容仅为Groovy入门的基础知识,Groovy还有更多高级特性如AST转换、GroovyShell、 Grape依赖管理等,等待你进一步探索。通过阅读《Groovy经典入门推荐版》PDF,你将能够全面了解这个语言,并迅速上手。

    Groovy入门教程

    ### Groovy入门教程知识点详解 #### 一、Groovy简介 **1.1 Groovy的定义** Groovy是一种基于JVM(Java虚拟机)的敏捷开发语言,它结合了多种现代编程语言的强大特性,如Python、Ruby和Smalltalk等。由于Groovy运行...

    Groovy中文版教程

    例如,变量声明可以省略类型,使用`def`关键字即可。此外,Groovy支持闭包,这是一种强大的代码块,常用于函数式编程。 2. **动态类型**:Groovy是动态类型的,这意味着变量的类型在运行时确定,而非编译时。这种...

    Groovy入门教程[参照].pdf

    Groovy 入门教程 Groovy 是一种基于 Java 语言的脚本语言,运行在 JVM 中,语法与 Java 相似,但抛弃了 Java 的一些烦琐的语法规则,提供了更加简洁和灵活的编程体验。 Groovy 的特点 1. 简洁的语法:Groovy 语法...

    groovy-api-chm

    Groovy对象可以通过`new`关键字创建,也可以通过`invokeConstructor`方法动态创建。 3. **集合操作**:Groovy对Java集合API进行了增强,提供了便利的列表和映射操作。例如,可以使用`each`、`collect`、`grep`等...

    groovy和Java相互调用1

    标题中的“Groovy和Java相互调用1”指的是在编程时如何在Groovy语言环境中调用Java类,以及反之,如何在Java程序中调用Groovy类。这是一种跨语言交互的方式,特别是在混合使用Groovy和Java的项目中非常常见。 ...

    Groovy学习笔记.pdf

    这通常包括安装Java Development Kit (JDK),因为Groovy是建立在Java之上的。确保你的系统已经安装了最新版本的JDK,然后可以从Groovy的官方网站下载对应操作系统的Groovy安装包。安装完成后,配置环境变量,将...

    apache-groovy-sdk-4.0.1下载

    Apache Groovy SDK 4.0.1 是一个重要的软件开发工具包,专为使用Groovy编程语言进行开发的程序员设计。Groovy是一种基于Java平台的动态、灵活的编程语言,它扩展了Java语言的功能,提供了简洁的语法和强大的元编程...

    groovy-all

    Groovy是一种动态、开源的编程语言,它是Java平台上的一个重要的补充。Groovy结合了Python、Ruby和Smalltalk等语言的特性,同时保留了与Java的无缝集成能力,使得它在脚本编写、Web开发、自动化测试等领域有着广泛的...

    eclipse安装groovy插件的步骤

    ### Eclipse 安装 Groovy 插件的详细步骤与使用指南 #### 一、Groovy 插件的安装 为了能够在 Eclipse 中使用 Groovy 进行开发,首先需要安装 Groovy 插件。以下是详细的安装步骤: 1. **下载 GroovyEclipse.zip ...

    Groovy应用(基本操作)

    例如,可以使用`def`关键字定义变量,无需指定类型: ```groovy def var = "Hello, Groovy!" println var ``` 2. **数据类型** Groovy支持基本的数据类型,如整型(int)、浮点型(float)、布尔型(boolean...

Global site tag (gtag.js) - Google Analytics