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