Groovy:this.metaClass与instance.metaClass

Groovy:this.metaClass与instance.metaClass,groovy,this,metaclass,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 c

我在书中遇到了下面的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
所以我很困惑:

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

  • 为什么是这个。元类!=实例.元类

    它涉及groove对字段的访问

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

    • 当从“”内部访问实例字段时,groovy只需直接访问该字段,不调用getFieldName()。在我们的示例中,当我使用“this”时,我位于“内部””;因此“this.metaClass”将直接访问“metaClass

    • 最后,getMetaClass()返回一个HandleMetaClass对象,而内部元类是一个MetalassImpl对象。所以这个元类=实例.元类

  • 为什么这个.metaClass.say={->println“say”}会抛出MissingPropertyException

    • 元类的类型是MetaClassImpl

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

  • 代码示例(针对问题1):

    代码示例(针对问题2):


    如果将其更改为
    assert this.class.metaClass==instance.metaClass
    ,它将通过。为什么?应该this.class.metaClass==Person.metaClass吗?在这里找到了一个更好的答案,实际上,那就是我。那么,当当前类中没有定义
    metaClass
    时,它是如何进行字段访问的呢?也许它的访问修饰符在它的
    对象
    超类中受到保护,也许?但在任何情况下,根据groovy文档,为了获得字段访问权,需要从定义属性的类中访问属性<代码>元类
    未在Person子类中定义,因此我想知道字段访问是如何完成的。
    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()
    
    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)