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
Так что я совсем запутался
- почему this.metaClass не равно instance.metaClass?
- более того, я не могу использовать this.metaClass для внедрения новых методов; groovy говорит мне, что this.metaClass не имеет такого свойства, которое я намеревался внедрить.
- Что означает "org.codehaus.groovy.runtime.HandleMetaClass@245b4bdc[groovy.lang.MetaClassImpl@245b4bdc[класс Person]]"? Я знаю, что "245b4bdc" может быть указателем объекта. Но почему HandleMetaClass и MetaClassImpl имеют одинаковое значение указателя "245b4bdc"?
В настоящее время я выяснил, что @ 245b4bdc не является "ссылкой на объект", поэтому HandleMetaClass @ 245b4bdc не обязательно совпадает с экземпляром MetaClassImpl @ 245b4bdc. Мы можем использовать метод Object.is(), чтобы определить, являются ли они одинаковыми. (Я сделал это, результат равен false)
1 ответ
почему this.metaClass!= instance.metaClass?
Это вовлекает доступ паза к полям.
При доступе к полю экземпляра "извне", groovy фактически вызывает функцию getFieldName(). В моем примере, когда я использую "экземпляр", я нахожусь снаружи; Поэтому instance.metaClass будет вызывать instance.getMetaClass ().
При доступе к полю экземпляра "изнутри", groovy просто напрямую обращается к полю, getFieldName() не вызывается. В нашем примере, когда я использую "это", я нахожусь на "внутри"; Таким образом,this.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','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)