我們知道,在Java語言中,我們能夠獲取到Java語言的動態性,主要是通過它的反射機制來實現的。而在Groovy語言中,我們將會有很多方式來獲取它的動態性,比如MOP等等。因此,在Groovy語言中,我們需要在運行期內調用某個方法,將不會使用反射機制,雖然我們仍然能夠在Groovy語言中使用反射機制來達到目的;而是使用MOP機制,或者使用"duck type"。因為這些機制都比反射來得方便和靈活。
這是否說明,我們在Groovy語言的程序開發過程中將不再使用到反射機制呢?我們說,反射機制除了能夠讓我們在運行期內動態的調用方法以外,還有一個很重要的功能是自省功能,就是讓我們能夠在運行期內知道一個對象它本身的一個信息,如屬於哪個Class,有哪些屬性和方法,它的Class是繼承了哪個父類,還是實現了哪些接口,等等。當然,還有一個很重要的功能是,能夠在運行期內實例化一個類,這也是我們經常要用到的。
因此,在我們的Groovy語言編碼過程中,反射機制仍然將扮演很重要的角色,MOP機制只是將反射機制的一些很弱的功能進行了擴展。
首先,我們有一個簡單的類:
package reflect;
class Testor3 {
public a
def b
private String c
}
我們已經獲得了一個對象,如下所示:
def t = new Testor3()
現在,我們想知道該對象"t"的類名,在Java語言中,我們必須這樣獲取:
println t.getClass().getName()
在Groovy語言中,由於我們廣泛的使用了Gpath,上面的語句當然可以簡化成下面的樣子:
println t.class.name
上面的兩條語句都將打印如下的結果:
reflect.Testor3
如果我們只想獲取該對象的Class名,而不想帶著包名,那麼將是如下的樣子:
println t.class.simpleName
打印的結果為:
Testor3
值得注意的是,雖然使用Gpath來獲取Class相當簡單,但也不是任何時候都可以這樣獲取的。比如:
def map = [:]
println map.class
它的打印結果將是:
null
如果你有下面的語句:
println map.class.simpleName
那麼,運行它,你將得到一個空指針的違例。
在這個時候,"getClass"方法仍將派上用場:
println map.getClass()
println map.getClass().simpleName
println map.getClass().name
上面的語句都能夠正確運行,得到的結果為:
class java.util.LinkedHashMap
LinkedHashMap
java.util.LinkedHashMap
得到了對象的Class以後,我們接著想得到的是它的屬性。獲取對象的屬性有兩個方法:一是獲取"fields";二是獲取"declaredFields"。前一個方法能夠獲取到該對象的公有屬性;後一個方法獲取的對象的所有屬性。如:
def t = new Testor3()
def cls = t.class
println cls.fields
println cls.declaredFields
運行結果為:
{public java.lang.Object reflect.Testor3.a, public static java.lang.Long reflect.Testor3.__timeStamp}
{public java.lang.Object reflect.Testor3.a, private java.lang.Object reflect.Testor3.b, private java.lang.String reflect.Testor3.c, transient groovy.lang.MetaClass reflect.Testor3.metaClass, public static java.lang.Long reflect.Testor3.__timeStamp, static java.lang.Class reflect.Testor3.class$groovy$lang$MetaClass, static java.lang.Class reflect.Testor3.class$org$codehaus$groovy$runtime$ScriptBytecodeAdapter, static java.lang.Class reflect.Testor3.class$0}
接著,我們就想獲取該對象的繼承關系,如有哪個父類,有哪個接口等等。我們通過"superclass"可以獲取到該對象的父類,而通過"interfaces"可以獲取到它實現的接口。如,我們有如下的關系:
package reflect;
interface A1
{
}
interface A2
{
}
class A implements A1,A2
{
}
interface B1
{
}
class B extends A implements B1
{
}
那麼,我們就可以通過如下的編碼來獲取他們之間的繼承關系了:
def m = []
A.interfaces.each{
m << it.name
}
println m
def m1 = []
B.interfaces.each{
m1 << it.name
}
println m1
println B.superclass
運行結果為:
["reflect.A1", "reflect.A2", "groovy.lang.GroovyObject"]
["reflect.B1"]
class reflect.A
最後一個對我們非常有用的反射功能就是在運行期內實例化一個對象,請看下面的例子:
Class c = Class.forName('reflect.Testor3')
def t1 = c.newInstance()
t1.a = 'hello'
println t1.a
可以看到,基本上和Java語言的反射機制一樣使用,但由於Groovy語言的"duck type"功能,使得我們通過"newInstance"方法實例化一個對象以後,並不需要像Java語言那樣,進行過強制類型轉換後才能使用,而是可以直接使用。上面的代碼,在Java語言中將會是下面的樣子:
try
{
Class c = Class.forName("reflect.Testor3");
Testor3 t1 = (Testor3)c.newInstance();
t1.a = "hello";
System.out.println(t1.a);
}
catch(Exception e)
{
e.printStackTrace();
}
而運行的結果都同樣是:
hello