美文网首页
Groovy方法调用说明

Groovy方法调用说明

作者: Azur_wxj | 来源:发表于2017-10-12 00:11 被阅读425次

    在一个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”); //断言为真
        
        上述情况总,因为元类中方法没有有参数的方法,但是类中本身有带参数的同名方法,所以会调用。实际上,在发现元类中不存在这个方法后就会在本类中寻找是否有该方法,如果有就调用,然后找到了,程序于是就终止了。

    相关文章

      网友评论

          本文标题:Groovy方法调用说明

          本文链接:https://www.haomeiwen.com/subject/nhiwyxtx.html