我們知道,除了使用hook來攔截方法以外,我們還可以通過各種方式來實現方法。如,我們可以在類裡直接實現方法;我們可以通過ExpandoMetaClass在運行期內添加方法;我們還可以通過ExpandoMetaClass在運行期內單獨給一個對象添加方法。
所有的這些直接添加方法的途徑,如果存在hook的話,都是要被hook攔截的。所以,我們可以說,系統是優先調用hook的。
而hook的調用順序,我們在上一篇《Groovy探索之MOP 十一 運行期內覆蓋invokeMethod》已經談到過了。
本篇要談到,卻是除了hook方法以外的方法實現途徑的調用順序的問題。
我們都知道,如果有如下的一個類:
class Foo {
def getFoo()
{
'foo'
}
}
那麼,我們可以通過如下的方法來調用它的方法:
def foo = new Foo()
println foo.foo
運行結果為:
foo
這就是我們的Gpath。
當然,我們也可以通過ExpandoMetaClass在運行期內添加這個"get"方法,如下:
Foo.metaClass.getFoo = {
->
'meta'
}
如果我們再做下面的測試:
def foo = new Foo()
println foo.foo
那麼,運行結果為:
meta
從結果可以看出,在運行期內通過ExpandoMetaClass添加的方法是會覆蓋類本身的方法的。
我們知道,在運行期內給類添加方法還有一種方式,即:
def mc = new ExpandoMetaClass(Foo.class,true)
mc.getFoo = {
->
'far'
}
mc.initialize()
下面,我將對上面的Foo類,在運行期內同時實行上面的兩種方法的添加方式,然後在做測試,看看結果將會如何?
代碼如下:
Foo.metaClass.getFoo = {
->
'meta'
}
def mc = new ExpandoMetaClass(Foo.class,true)
mc.getFoo = {
->
'far'
}
mc.initialize()
def foo = new Foo()
println foo.foo
}
運行結果為:
far
由此可見,後一種在運行期內添加方法的方式是會覆蓋前一種在運行期內添加方法的方式的。
除此之外,我們還有一種在運行期內給對象添加方法的方式,如下:
def emc = new ExpandoMetaClass( foo.class, false )
emc.getFoo = {
->
"test" }
emc.initialize()
foo.metaClass = emc
最後,我們還將寫代碼來測試這最後一種方式與前幾種方式的調用順序。代碼如下:
def mc = new ExpandoMetaClass(Foo.class,true)
mc.getFoo = {
->
'far'
}
mc.initialize()
def foo = new Foo()
def emc = new ExpandoMetaClass( foo.class, false )
emc.getFoo = {
->
"test" }
emc.initialize()
foo.metaClass = emc
println foo.foo
運行結果為:
test
可以看出,使用上面的方式在運行期內給一個對象添加的方法,會覆蓋通過ExpandoMetaClass在運行期內給一個類添加的方法。