2015-12-24 4 views
8

В этой книге я столкнулся со строгим кодом сценария. И это породило некоторые странные результаты для меня.Groovy: this.metaClass Versus instance.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:  [email protected][class Person] 
instance.metaClass: [email protected][[email protected][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. Что такое «[email protected]c [[email protected] [class Person]]» означает? Я знаю, что «245b4bdc» может быть указателем на объект. Но почему HandleMetaClass и MetaClassImpl имеют одно и то же значение указателя «245b4bdc»?

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

+1

Если вы измените его на 'утверждают this.class. metaClass == instance.metaClass', он проходит. – bdkosher

+0

Почему? Должен ли this.class.metaClass == Person.metaClass? – Guocheng

+0

Нашел лучший ответ здесь, https://stackoverflow.com/a/45407488/42769, на самом деле, это я. –

ответ

3
  1. почему this.metaClass! = Instance.metaClass?

    Он включает в себя доступ к каналам.

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

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

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

  2. Почему this.metaClass.say = {-> Println "говорят"} будет бросками 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) 
+0

Итак, как он делает доступ к полю 'metaClass', если он не был определен в текущем классе? Возможно, это модификатор доступа защищен в суперклассе 'Object', может быть? Но в любом случае, чтобы получить доступ к полям, свойство должно быть доступно из класса, который его определяет, согласно groovy doc. 'metaClass' не определен в подклассе Person, поэтому мне интересно, как выполняется доступ к полям. – solstice333

+0

Нет, это неправильный ответ. См. Здесь, https://stackoverflow.com/a/45407488/42769. –