我們都知道,在Groovy語言中,我們可以使用MOP特性在運行期內添加屬性或方法。
這種添加包括兩個層面的添加:
第一, 是給一個類添加屬性或方法。也就是說,如果我們在運行期內給一個類添加了屬性或方法,那麼添加了以後,所有這個類實例化的對象,都將擁有了這個屬性或方法。
第二, 第二,是給一個對象添加屬性或方法。也就是說,如果我們在運行期內給一個對象添加了屬性或方法,那麼添加了以後,只有這個對象才擁有這個屬性或方法。換句話說,如果我們再給這個對象的類實例化一個對象,那麼該對象則不能擁有我們剛添加的那個屬性或方法。
真的是這樣嗎?讓我們舉幾個例子來看看吧。
使用ExpondoMetaClass在運行期內給一個類添加屬性或方法是我們最最常用的一種在運行期內添加屬性或方法的方法。比如,我們有如下的一個類:
class Testor1 {
}
現在,我們就嘗試著使用ExpondoMetaClass在運行期內給Testor1添加一個方法,然後來測試它:
def t = new Testor1()
try
{
println 't invoke far'
t.far()
}
catch(Exception e)
{
}
Testor1.metaClass."far" = {
->
println 'far'
}
def t1 = new Testor1()
println 't1 invoke far'
t1.far()
def t2 = new Testor1()
println 't2 invoke far'
t2.far()
測試很簡單,我們在添加方法之前實例化一個Testor1對象,然後再添加方法之後實例化兩個Testor1對象,分別來測試它們。
結果為:
t invoke far
t1 invoke far
far
t2 invoke far
far
從結果可以看出:在添加方法之前實例化的那個對象不能調用"far"方法,而添加方法之後實例化的兩個對象都可以調用"far"方法。
這就是在運行期內給類添加方法或屬性的結果。
其實,使用MOP特性在運行期內給類添加屬性或方法還有一種方法來實現,它就是下面的這種方法:
def t = new Testor1()
try
{
println 't invoke far'
t.far()
}
catch(Exception e)
{
}
def mc = new ExpandoMetaClass(Testor1.class,true)
mc.far = {
->
println 'far'
}
mc.initialize()
def t1 = new Testor1()
println 't1 invoke far'
t1.far()
def t2 = new Testor1()
println 't2 invoke far'
t2.far()
}
就是使用ExpondoMetaClass類來實例化一個對象,如"def mc = new ExpandoMetaClass(Testor1.class,true)",再給該對象添加一個方法,如:
mc.far = {
->
println 'far'
}
然後,將這個對象實例化,如"mc.initialize()"。
上面代碼的運行結果為:
t invoke far
t1 invoke far
far
t2 invoke far
far
跟一種方法的結果一樣。
最後,我們來看看如何給一個對象在運行期內添加屬性或方法,以及它們的運行結果。
def t = new Testor1()
try
{
println 't invoke far'
t.far()
}
catch(Exception e)
{
}
def t1 = new Testor1()
def emc = new ExpandoMetaClass( Testor1.class, false )
emc.far = { println "far" }
emc.initialize()
t1.metaClass = emc
println 't1 invoke far'
t1.far()
def t2 = new Testor1()
try
{
println 't2 invoke far'
t2.far()
}
catch(Exception e)
{
}
我們還使用"def emc = new ExpandoMetaClass( Testor1.class, false )"語句來給一個對象添加屬性或方法,但需要記住的是,第二個參數是"false"。接著,我們就可以添加方法了:
emc.far = { println "far" }
最後,還要做兩件事,就是實例化該對象,並且把該對象賦值給t1對象的metaClass屬性。如:
emc.initialize()
t1.metaClass = emc
上面代碼的運行結果為:
t invoke far
t1 invoke far
far
t2 invoke far