2018年8月1日 星期三

呼叫方法的流程 (groovy 2.x 五)

官網連結
當你呼叫一個方法,你沒寫過這個方法,而且也不是 jar 檔裡的方法時,java 會出錯;但 groovy 不一定會出錯,是有一定的流程的

官網的圖,一開始就分有沒有實作 GroovyInterceptable,有實作就呼叫 invokeMethod,但如果沒有 invokeMethod,官網就沒畫了

※我參考官網的圖,有一個部分我並不十分了解,以下說明
Method exists in MetaClass or class,就這個不是很懂
Property exists in MetaClass or class 且還要是閉包才會呼叫,因為 property 是使用在屬性的,而閉包算是比較特殊的

以上這兩個我試的結果,感覺是兩個合起來,所以我認為是「閉包方法或 class」,這兩個好像沒有誰一定會先執行,我有等 30 分鐘再執行,有可能是另外一個執行

所以以下我就以這兩個合併的前提寫了以下的代碼,看圖除了 exception 外,有 5 個結果,但 invokeMethod 重複了,這要看有沒有實作 GroovyInterceptable 而定,所以實際上有 4 個結果


※有實作 GroovyInterceptable

class MyGroovy implements GroovyInterceptable {
    //  @Override
    //  Object invokeMethod(String methodName, Object args) {
    //      "1.方法名:${methodName},參數:${args}"
    //  }
    
    //  def abc(String p1, Object p2) {
    //        "2-1.參數一:${p1},參數二:${p2}"
    //  }
    
    def methodMissing(String methodName, Object args) {
        "3.方法名:${methodName},參數:${args}"
    }
    
    static void main(String[] args) {
    //  MyGroovy.metaClass.abc = { p1, p2 ->
    //      "2-2.參數一:${p1},參數二:${p2}"
    //  }
        MyGroovy m = new MyGroovy()
        println m.abc('xyz', 123)
    }
}

※全部註解打開,會先執行1,1如果註解,就會執行2,依此類推

※有2-1、2-2 這種的,不一定是 2-1 先執行,也有可能 2-2 先執行


※沒實作 GroovyInterceptable

class MyGroovy2 {
    //  def abc(String p1, Object p2) {
    //      "1-1.參數一:${p1},參數二:${p2}"
    //  }
    
    //  def methodMissing(String methodName, Object args) {
    //      "2.方法名:${methodName},參數:${args}"
    //  }
    
    @Override
    Object invokeMethod(String methodName, Object args) {
        "3.方法名:${methodName},參數:${args}"
    }
    
    static void main(String[] args) {
    //  MyGroovy2.metaClass.abc = { p1, p2 ->
    //      "1-2.參數一:${p1},參數二:${p2}"
    //  }
        
        MyGroovy2 m2 = new MyGroovy2()
        println m2.abc('xyz', 123)
    }
}




以上主要是有個類別是 final 類,如 String,沒辦法繼承它,也沒辦法改它,所以可以使用這個功能來新增

※測試

class Animal {
    static void main(String... aaa) {
        // ExpandoMetaClass.enableGlobally() // 據說 1.8.1 版就不需要也能成功了
        // new Animal().nonStaticMethod() // 還沒動態加載,所以找不到方法
    
        Animal.metaClass.constructor = { String s ->  // = 可改成 <<
            println "String constructor"
        } << { Integer i -> // 使用 << 可以增加 overloading 方法,= 不可以
            println "Integer constructor"
        }
    
        Animal.metaClass.static.staticMethod = { // = 可改成 <<
            println 'static method'
        }
    
        Animal.metaClass.nonStaticMethod = { // = 可改成 <<
            println 'nonStatic method'
        }
    
        Animal a = new Animal(8)
        Animal.staticMethod() // 不能使用 call()
        new Animal().nonStaticMethod() // 不能使用 call()
    }
}

※在新增方法後,在別的地方使用,還是沒有新增的方法,所以有了 ExpandoMetaClass.enableGlobally(),在新增方法前呼叫即可,但我沒試出來,一直都可以,找了網路上的文章,聽說是 1.8.1 不需要的樣子


沒有留言:

張貼留言