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

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

 

 

我们知道,除了使用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在运行期内给一个类添加的方法。

展开阅读全文

没有更多推荐了,返回首页