Groovy: this.metaClass Versus instance.metaClass

I came across the below groovy script code in a book. And that gave rise to some weird results for me.

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() 

it is output as follows:

 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 

So I'm very confused:

  • why is this.metaClass not equal to instance.metaClass?
  • Also, I cannot use this.metaClass to introduce new methods; groovy tells me that this.metaClass does not have the property that I wanted to introduce.
  • What does "org.codehaus.groovy.runtime.HandleMetaClass@245b4bdc [groovy.lang.MetaClassImpl @ 245b4bdc [Person]] mean" mean? I know that "245b4bdc" can be a pointer to an object. But why does HandleMetaClass and MetaClassImpl have the same pointer value "245b4bdc"?

Currently, I realized that @ 245b4bdc is not an " object reference ", so HandleMetaClass @ 245b4bdc is not necessarily the same instance as MetaClassImpl @ 245b4bdc . We can use the Object.is () method to determine if they are the same. (I did it, the result is false )

+8
metaclass this groovy
source share
1 answer
  • why this.metaClass! = instance.metaClass?

    It includes access to the fields.

    • When accessing the instance field from outside , groovy actually calls the getFieldName () function. In my example, when I use the " instance ", I am out ; Therefore, instance.metaClass will call instance.getMetaClass () .

    • When accessing an instance field from inside, "groovy just accesses the field, getFieldName () is not called. In our example, when I use this one , I'm inside "; So this.metaClass "will directly access metaClass ".

    • Finally, getMetaClass () returns a HandleMetaClass object, and the inner metaclass is a MetaClassImpl object . So this.metaClass! = Instance.metaClass .

  • Why does this.metaClass.say = {-> println "say"} throw a MissingPropertyException?

    • this.metaClass type is MetaClassImpl

    • MetaClassImpl is a low-level class that supports top-level classes (e.g. HandleMetaClass) for injection. It is not intended to be used directly by the Developer, so it does not support the injection method: xxxx.say = {-> println "say"} .

Sample code (for question 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() 

Sample code (for question 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) 
+3
source share

All Articles