Groovy探索之反射
我们知道,在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