Groovy: этот.metaClass и экземпляр.metaClass

Я столкнулся ниже с отличным кодом сценария в книге. И это дало мне странные результаты.

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[класс Person]]"? Я знаю, что "245b4bdc" может быть указателем объекта. Но почему HandleMetaClass и MetaClassImpl имеют одинаковое значение указателя "245b4bdc"?

В настоящее время я выяснил, что @ 245b4bdc не является "ссылкой на объект", поэтому HandleMetaClass @ 245b4bdc не обязательно совпадает с экземпляром MetaClassImpl @ 245b4bdc. Мы можем использовать метод Object.is(), чтобы определить, являются ли они одинаковыми. (Я сделал это, результат равен false)

1 ответ

Решение
  1. почему this.metaClass!= instance.metaClass?

    Это вовлекает доступ паза к полям.

    • При доступе к полю экземпляра "извне", groovy фактически вызывает функцию getFieldName(). В моем примере, когда я использую "экземпляр", я нахожусь снаружи; Поэтому instance.metaClass будет вызывать instance.getMetaClass ().

    • При доступе к полю экземпляра "изнутри", groovy просто напрямую обращается к полю, getFieldName() не вызывается. В нашем примере, когда я использую "это", я нахожусь на "внутри"; Таким образом,this.metaClass будет обращаться кметаклассу напрямую.

    • Наконец, getMetaClass() возвращает объект HandleMetaClass, а внутренний metaClass является объектом MetaClassImpl. Так что this.metaClass! = Instance.metaClass.

  2. Почему 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','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)
Другие вопросы по тегам