Groovy探索之MOP 八 运行期内给类和对象添加属性或方法

我们都知道,在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()

}

时间: 2016-12-18

Groovy探索之MOP 八 运行期内给类和对象添加属性或方法的相关文章

Groovy探索之MOP 十一 运行期内覆盖invokeMethod

我们很早就会使用Groovy语言的hook,即"invokeMethod"方法和其他的几个方法.我们会在一个类中实现"invokeMethod"方法,用来分派所有的或部分的在运行期内调用的该类实例的方法.这些我们在<Groovy探索之MOP 一 invokeMethod和methodMissing方法>已经详细的谈到过. 现在,我们已经深入的接触到了Groovy语言的MetaClass,更是也到处使用到了ExpandoMetaClass.我们都已经知道,

Groovy探索之MOP 七 运行期内的方法和属性分析

在Groovy语言里,运行期内的方法和属性分析有三种方式,它们分别是: 第一, 继承自Java语言的反射方式. 第二, 使用"respondsTo"和"hasProperty"方法. 第三, 使用"hasMetaMethod"和"hasMetaProperty"方法. 以上三种方法都能在运行期内分析某个方法或属性是否存在,相信我们看到这里,一定会想,它们之间是否有什么区别呢? 漫谈这三种运行期内的方法和属性分析方式以及它们之间

Groovy探索之MOP 六 运行期内添加构造器和静态方法

构造器是我们喜欢重载的一个方法,因为我们在实例化一个类的时候,会遇到各种各样的情况,比如在某些情况下,一系列类的实例可能有一些相同值的属性,这时候,我们在实例化对象时,就不希望把这些相同的值分别注入到每一对象中,这样的工作很繁琐. 这时候,我们就会重载构造器,但一些时候,比如一些Bean对象,它们的属性很多,我们就不好在类中重载很多构造器.比如,我们有如下的一个GroovyBean类: class Reader { String province String city String name

Groovy探索之MOP 十二 方法的调用顺序

我们知道,除了使用hook来拦截方法以外,我们还可以通过各种方式来实现方法.如,我们可以在类里直接实现方法:我们可以通过ExpandoMetaClass在运行期内添加方法:我们还可以通过ExpandoMetaClass在运行期内单独给一个对象添加方法. 所有的这些直接添加方法的途径,如果存在hook的话,都是要被hook拦截的.所以,我们可以说,系统是优先调用hook的. 而hook的调用顺序,我们在上一篇<Groovy探索之MOP 十一 运行期内覆盖invokeMethod>已经谈到过了.

Groovy探索之MOP 十四 对Java类使用Groovy语言的MOP

既然Groovy语言是Java语言的扩展,那么我们在使用Groovy语言的时候,就很难与Java语言真正脱得了干系,那怕我们是在做一个纯Groovy语言的项目,如Grails项目.我们可能在Groovy代码中会用到遗留的Java类和包:也可能是为了性能的原因,我们不得不在Groovy语言中使用到Java类:等等. 如果我们要对于Java类使用Groovy语言的MOP,比如我们想给一个Java类的对象在运行期内添加一个方法.那么我们该怎么办呢? 比如,我们有如下的一个Java类: //(Java代

Groovy探索之MOP 二 对类属性的各种操作

我们谈到MOP,即"元对象协议",就是对类或对象的各个元素,如名称.方法.属性等等,在运行期进行实时变化,如修改方法名.属性名,动态增加方法.属性等等的一类编程的统称. 比如前面我们所谈到过的"invokeMethod"和"methodMissing"两个方法,就可以用来使得我们在运行期动态的给一个类增加方法,值得注意的是,这种增加是类级别的,即一个类所有的对象都可以增加方法. 既然说过了在运行期给一个类动态的增加方法,那么相应的,在运行期给一个

Groovy探索之MOP 十五 方法名的动态性

到目前为止,我们的<Groovy探索之MOP>系列已经谈到了使用ExpandoMetaClass的方方面面,但值得注意的是,我们通过ExpandoMetaClass给一个类在运行期内添加一个方法,不管是普通方法还是静态方法,我们都是添加一个确定方法名的方法.即我们添加一个方法名为A的方法,然后才能使用这个方法A. 然而,方法名的动态性,其实是我们早已接触过的事情,比如在<Groovy探索之invokeMethod方法>里,我们就可以创建形如"sortByXxxxx()&q

Groovy探索之MOP 四 使用ExpandoMetaClass来实现Mixin

国内很多的文章都在说Groovy语言的Mixin机制就是Groovy语言的Categories机制.其实,在外面的Blog上,大量有人在讨论Groovy语言应该如何实现它自己的Mixin机制,这就是说明Groovy语言的Mixin机制还没有定型,处在讨论之中.Categories机制当然也能实现部分的Mixin功能,就像Java语言的接口机制,还有组合等等,都能实现部分的Mixin功能.就像C++语言的多继承一样,这些"古老"的机制都能或多或少的实现部分的Mixin功能. 其实,Mix

Groovy探索之MOP 五 针对接口类型的动态性

这里所说的接口类型,在Java语言和Groovy语言中,当然是既包括了基类类型和接口.所谓"接口类型的动态性",指的是在运行期内给基类或接口动态的添加方法,使得基类以及它的子类.接口的实现,都能访问这些方法. 这个功能一向是我比较感兴趣的一个功能.因为我们在编程的实践中,会使用各种各样的应用API,还有JDK,在使用它们的过程中,可能有一些接口及它们的子类我们会经常使用到,但是在使用的过程中,我们又感到非常的不方便.这时候,我们可以使用Categories机制来对我们所使用的类进行扩充