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
所以我很困惑:
>为什么this.metaClass不等于instance.metaClass?
>更进一步,我不能使用this.metaClass来注入新方法; groovy告诉我this.metaClass没有这样的属性,我打算注入.
>“org.codehaus.groovy.runtime.HandleMetaClass@245b4bdc [groovy.lang.MetaClassImpl@245b4bdc [class Person]]”是什么意思?我知道“245b4bdc”可能是对象指针.但是为什么HandleMetaClass和MetaClassImpl具有相同的指针值“245b4bdc”?
目前,我发现@ 245b4bdc不是“对象引用”,因此HandleMetaClass @ 245b4bdc不一定与MetaClassImpl @ 245b4bdc相同.我们可以使用Object.is()方法来判断它们是否相同.(我这样做,结果是假的)
解决方法
它涉及沟槽进入田地.
>从“outside”访问实例字段时,groovy实际上调用函数getFieldName().在我的例子中,当我使用“实例”时,我在外面;因此instance.metaClass将调用instance.getMetaClass().
>从“inside”访问实例字段时,groovy只是直接访问该字段,不调用getFieldName().在我们的例子中,当我使用“this”时,我处于“内部”;所以“this.metaClass”将直接访问“metaClass”.
>最后,getMetaClass()返回一个HandleMetaClass对象,而内部metaClass是一个MetaClassImpl对象.所以this.metaClass!= instance.metaClass.
>为什么this.metaClass.say = { – > println“say”}会抛出MissingPropertyException?
> this.metaClass的类型是MetaClassImpl
> MetaClassImpl是一个低级类,它支持高级类(例如HandleMetaClass)进行注入.它不适合开发人员直接使用,因此它不支持注入方式:xxxx.say = { – > println“say”}.
代码示例(问题1):
class Person{ def work(){ println "work()" } def sports=['basketball',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)