Groovy:this.metaClass与instance.metaClass

时间:2015-12-24 08:24:46

标签: groovy this metaclass

我在书中遇到了下面的groovy脚本代码。它给我带来了一些奇怪的输出。

class Person{
  def work(){
    println "work()"
  }
  def sports=['basketball','football','voleyball']
  def methodMissing(String name, args){
    if(name in sports){
        println "injected ${name} into Person class"
        Person instance=this
        println "this.metaClass:\t\t${this.metaClass}"
        println "instance.metaClass:\t${instance.metaClass}"
        assert this.metaClass==instance.metaClass
    }else{
        println "no such method:${name}() in Person class"
    }
  }
}
def jack=new Person()
jack.football()

它的输出如下:

injected football into Person class
this.metaClass:     groovy.lang.MetaClassImpl@245b4bdc[class Person]
instance.metaClass: org.codehaus.groovy.runtime.HandleMetaClass@245b4bdc[groovy.lang.MetaClassImpl@245b4bdc[class Person]]
Caught: Assertion failed: 
//I did not paste the detailed assertion here for simplicity

所以我很困惑:

  1. 为什么this.metaClass不等于instance.metaClass?
  2. 更进一步,我不能使用this.metaClass来注入新方法; groovy告诉我this.metaClass没有这样的属性,我打算注入。
  3. “org.codehaus.groovy.runtime.HandleMetaClass@245b4bdc [groovy.lang.MetaClassImpl@245b4bdc [class Person]]”是什么意思?我知道“245b4bdc”可能是对象指针。但为什么HandleMetaClass和MetaClassImpl具有相同的指针值“245b4bdc”?
  4. 目前,我发现@ 245b4bdc不是“对象引用”,所以 HandleMetaClass @ 245b4bdc 不一定与 MetaClassImpl @ 245b4bdc相同即可。我们可以使用Object.is()方法来判断它们是否相同。(我这样做,结果是 false

1 个答案:

答案 0 :(得分:3)

  1. 为什么this.metaClass!= instance.metaClass?

    它涉及凹槽访问领域。

    • 从" 外部"访问实例字段时,groovy实际上调用函数getFieldName()。在我的示例中,当我使用" 实例"时,我在外部;因此 instance.metaClass 将调用 instance.getMetaClass()

    • 从" 里面"访问实例字段时,groovy只是直接访问该字段,不会调用getFieldName()。在我们的示例中,当我使用" 这个"时,我在" 里面&#34 ;;所以" this.metaClass "将访问" metaClass "直接

    • 最后,getMetaClass()返回 HandleMetaClass 对象,而内部metaClass是 MetaClassImpl 对象。所以 this.metaClass!= instance.metaClass

  2. 为什么this.metaClass.say = { - > println"说"}会抛出MissingPropertyException?

    • this.metaClass的类型是MetaClassImpl

    • MetaClassImpl是一个低级类,支持高级类(例如HandleMetaClass)进行注入。它不适合开发人员直接使用,因此它不支持注入方式: xxxx.say = { - > println"说"}

  3. 代码示例(问题1):

    class Person{
      def work(){
        println "work()"
      }
      def sports=['basketball','football','voleyball']
      def methodMissing(String name, args){
        if(name in sports){
            Person instance=this
    
            println "this.metaClass:\n\t${this.metaClass}"
            println "instance.metaClass:\n\t${instance.metaClass}"
            //output: false
            println "this.metaClass.is(instance.metaClass):\n\t${this.metaClass.is(instance.metaClass)}"
    
            //output: true
            println "this.getMetaClass().is(instance.getMetaClass()):\n\t${this.getMetaClass().is(instance.getMetaClass())}"
    
        }else{
            println "no such method:${name}() in Person class"
        }
      }
    }
    def jack=new Person()
    jack.football()
    jack.football()
    

    代码示例(问题2):

    class Cat{}
        def a=new groovy.lang.MetaClassImpl(Cat)
    try{
        a.say={->println "say"}
    }catch(MissingPropertyException e){
        println "[Fail]\n\tcan not inject method say() into MetaClassImpl class.\n"
    }
    
    def b=new org.codehaus.groovy.runtime.HandleMetaClass(a)
    println b
    b.say={->println "[say]"}
    println "[OK]\n\tcan inject method say() into HandleMetaClass class\n"
    def method=b.getMetaMethod("say")
    method.invoke(this)