Groovy方法调用说明

在一个Groovy应用中,会调用三种对象:

  1. POJO 普通java对象
    extends java.lang.Object
  2. POGO 普通Groovy对象
    extends java.lang.Object
    implements groovy.lang.GroovyObject
  3. Groovy拦截器
    extends java.lang.Object
    implements groovy.lang.GroovyInterceptable
    [注意:interface groovy.lang.GroovyInterceptable extend groovy.lang.GroovyObject][GroovyInterceptable中没有抽象方法,它只是起标记作用的接口]

而在Groovy中,动态地注入方法、调用方法、属性就是使用元类metaClass来完成的(类似于Java的反射机制),请求的方法会被委托到这个类。

  1. 对于POJO而言,它是一个普通的java对象,甚至有可能是一个定义在jdk中的类,原生不可能有metaClass。为了实现这一功能,Groovy维护一个名为“MetaClassRegistry”的Map类对象,对于每一个POJO都能找到其对应的metaClass。
    在POJO的metaClass定义的方法和拦截器都优先于POJO中定义的方法
    考虑下面的例子,有一个java类:
    public class Dog {
        public void bark(){
            System.out.println("Wow");
        }
    }
    
    下面在Groovy脚本文件中有如下代码:
    Dog.metaClass.bark={->'don't bark!'}
    println  new Dog().bark()
    
    上述代码输出“don't bark!”,而不是"Wow"
  2. 对于一个拦截器对象,在其上调用的所有方法都会被代理到invokeMethod上,无论存不存在。
    class MyInterceptor implements groovy.lang.GroovyInterceptable{
        def introduceLang(){
            "Groovy"
        }
        def invokeMethod(String name,args){ //注意invokeMethod的签名
            "Hello! Welcome to use MyInterceptor."
        }
    }
    
    println(new MyInterceptor().introduceLang())
    println(new MyInterceptor().unknownMethod())
    
    上述定义了一个拦截器MyInterceptor,然后在拦截器实例上调用了一个存在的方法introduceLang以及不存在的方法unknownMethod,但是它们的输出都是“Hello! Welcome to use MyInterceptor.”。即无论方法存在与否,拦截器都会路由到invokeMethod上。
  3. 如果是POGO对象,它内部就有一个metaClass的属性,指向它的元类。在上面调用方法的路由规则比较复杂:
    POGO上的方法调用

    由于拦截器是特殊的POGO,所以第一步先判断是否是拦截器,如果是就按照第2条路由;否则看看方法在不在元类中,如果在就直接调用(即元类方法优先级高于自身方法),不然就看是否在类中;否则看是否存在同名的闭包属性,如果有则调用闭包;否则看看是否存在一个特殊的方法methodMissing方法,如果有就调用它;否则看看有没有invokeMethod方法(默认实现是抛出异常),如果有则调用,如果没有就抛出异常。
    下面是一些说明,其中的类都是POGO(且不是拦截器):
    • class ClassWithInvokeOnly{
        def invokeMethod(String name,args){'invoke called'}
      }
      def obj=new ClassWithInvokeOnly();
      assert 'invoke called'==obj.unknownMethod(); //断言为真
      
      路由到达最后一步,因为它存在invokeMethod,所以被调用了。
    •   class ClassWithInvokeOnly{
          def methodMissing(String name,args){ //注意方法签名
              'missing called'
          }
        }
        def obj=new ClassWithInvokeOnly();
        assert 'missing called'==obj.unknownMethod();  //断言为真
      
      路由到达倒数第二步,因为它存在methodMissing,所以被调用。
    •   class ClassWithInvokeOnly{
            def closure={
                'closureString'
            }
        }
        def obj=new ClassWithInvokeOnly();
        assert 'closureString'==obj.closure();//断言为真
      
      调用到倒数第三步,因为有同名闭包属性,所以被调用。
    •   class ClassWithInvokeOnly{
            def sayHello(){
                'hello'
            }
        }
        ClassWithInvokeOnly.metaClass.sayHello={
            'metaClass hello'
        }
        def obj=new ClassWithInvokeOnly();
        assert 'metaClass hello'==obj.sayHello(); //断言为真
      
      路由到第二步,元类中的方法会覆盖类中原本的同名方法。
      但是考虑下面的情况:
        class ClassWithInvokeOnly{
            def sayHello(name){
                'hello '+name
            }
        }
        ClassWithInvokeOnly.metaClass.sayHello={
            'metaClass hello'
        }
        def obj=new ClassWithInvokeOnly();
        assert 'hello Bob'==obj.sayHello(“Bob”); //断言为真
      
      上述情况总,因为元类中方法没有有参数的方法,但是类中本身有带参数的同名方法,所以会调用。实际上,在发现元类中不存在这个方法后就会在本类中寻找是否有该方法,如果有就调用,然后找到了,程序于是就终止了。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,580评论 18 139
  • Groovy学习目录-传送门 元编程(Metaprogramming)->百度百科 Groovy语言支持两种类型的...
    化作春泥_阅读 9,033评论 0 19
  • groovy是什么 Groovy 是下一代的Java语言,跟java一样,它也运行在 JVM 中。 作为跑在JVM...
    ronaldo18阅读 671评论 0 4
  • Groovy简介 Groovy是基于Java平台开发的一门强大的、具有Optional类型,多功能性的动态语言,它...
    Goach阅读 1,755评论 0 3
  • 一个朋友晚上发来消息,说自己背着男友和别人偷腥了,发消息来问我怎么看。 其实我一开始是决绝表达我的观点的,我也在纠...
    麾毛杆儿阅读 693评论 4 0