當你呼叫一個方法,你沒寫過這個方法,而且也不是 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 不需要的樣子
沒有留言:
張貼留言