Groovy instance.metaclass vs this.metaclass

2019-02-20 00:37发布

i have the flowing script:

task myTask {}

class Person {

     Person() {
        Person instance = this
        println this.metaClass.class.name
        println this.getMetaClass().class.name
        println instance.metaClass.class.name
        println instance.getMetaClass().class.name
    }
}

Person person = new Person()

And the output is :

groovy.lang.MetaClassImpl
groovy.lang.MetaClassImpl
org.codehaus.groovy.runtime.HandleMetaClass
org.codehaus.groovy.runtime.HandleMetaClass

can anyone explain to me what is going on ?

thanks in advance.

1条回答
姐就是有狂的资本
2楼-- · 2019-02-20 01:09

Take a look at this class,

class Person {

    def a, b

    Person() {
        a = this
        b = this
        println "this $this"
        println "a $a"
        println "b $b"
    }

    def printAll() {
        println "this.metaClass ${this.metaClass}"
        println "this.class.metaClass ${this.class.metaClass}"
        println "a.metaClass ${a.metaClass}"
        println "b.metaClass ${b.metaClass}"
    }
}

enter image description here

Take a look at the screenshot of the groovysh. It might give you a little hint about what's going on.

  1. p and q are two different objects, but
  2. p.metaClass is the same as q.metaClass, and
  3. printAll prints exactly the same thing for both, p and q
  4. a.metaClass and b.metaClass are holding this.class.metaClass, not this.metaClass, you see

There is only one object created of MetaClassImpl, and also only one of HandleMetaClass, for Person. And no matter how many times you instantiate Person, they will be assigned to the instance. But, when you expand any of that instance, only then a new HandleMetaClass object will be created -- just for that particular object; and this time HandleMetaClass will be holding not MetaClassImpl, but ExpandoMetaClass instead.

See the screenshot below,

enter image description here

Now, to answer your question, this.metaClass is a special case, like this itself. It doesn't give you the handle, HandleMetaClass object, so you can't expand over metaClass of this -- directly; and there is no sense in that either, because then all other future instances will share that expansion.

If you really want that behaviour then you can pass this to some other variable, i.e. instance = this, as you did in the constructor, and then you can expand over that instance -- and that expansion would be true for this and all other future instances. But then, why not add the behaviour to class itself, in the first place. Why expand?

查看更多
登录 后发表回答