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中,動態(tài)地注入方法、調用方法、屬性就是使用元類metaClass來完成的(類似于Java的反射機制),請求的方法會被委托到這個類。

  1. 對于POJO而言,它是一個普通的java對象,甚至有可能是一個定義在jdk中的類,原生不可能有metaClass。為了實現(xiàn)這一功能,Groovy維護一個名為“MetaClassRegistry”的Map類對象,對于每一個POJO都能找到其對應的metaClass。
    在POJO的metaClass定義的方法和攔截器都優(yōu)先于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對象,它內(nèi)部就有一個metaClass的屬性,指向它的元類。在上面調用方法的路由規(guī)則比較復雜:
    POGO上的方法調用

    由于攔截器是特殊的POGO,所以第一步先判斷是否是攔截器,如果是就按照第2條路由;否則看看方法在不在元類中,如果在就直接調用(即元類方法優(yōu)先級高于自身方法),不然就看是否在類中;否則看是否存在同名的閉包屬性,如果有則調用閉包;否則看看是否存在一個特殊的方法methodMissing方法,如果有就調用它;否則看看有沒有invokeMethod方法(默認實現(xiàn)是拋出異常),如果有則調用,如果沒有就拋出異常。
    下面是一些說明,其中的類都是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();  //斷言為真
      
      路由到達倒數(shù)第二步,因為它存在methodMissing,所以被調用。
    •   class ClassWithInvokeOnly{
            def closure={
                'closureString'
            }
        }
        def obj=new ClassWithInvokeOnly();
        assert 'closureString'==obj.closure();//斷言為真
      
      調用到倒數(shù)第三步,因為有同名閉包屬性,所以被調用。
    •   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”); //斷言為真
      
      上述情況總,因為元類中方法沒有有參數(shù)的方法,但是類中本身有帶參數(shù)的同名方法,所以會調用。實際上,在發(fā)現(xiàn)元類中不存在這個方法后就會在本類中尋找是否有該方法,如果有就調用,然后找到了,程序于是就終止了。
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,578評論 19 139
  • Groovy學習目錄-傳送門 元編程(Metaprogramming)->百度百科 Groovy語言支持兩種類型的...
    化作春泥_閱讀 9,200評論 0 19
  • groovy是什么 Groovy 是下一代的Java語言,跟java一樣,它也運行在 JVM 中。 作為跑在JVM...
    ronaldo18閱讀 773評論 0 4
  • Groovy簡介 Groovy是基于Java平臺開發(fā)的一門強大的、具有Optional類型,多功能性的動態(tài)語言,它...
    Goach閱讀 1,844評論 0 3
  • 一個朋友晚上發(fā)來消息,說自己背著男友和別人偷腥了,發(fā)消息來問我怎么看。 其實我一開始是決絕表達我的觀點的,我也在糾...
    麾毛桿兒閱讀 864評論 4 0

友情鏈接更多精彩內(nèi)容