Groovy:this.metaClass 与 instance.metaClass [英] Groovy: this.metaClass Versus instance.metaClass
问题描述
我在书中遇到过下面的groovy脚本代码.它对我产生了一些奇怪的输出.
I have encountered below groovy script code in the book . And it generated some strange outputs to me.
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: ${this.metaClass}"
println "instance.metaClass: ${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[class Person]]"是什么意思?我知道245b4bdc"可能是对象指针.但是为什么 HandleMetaClass 和 MetaClassImpl 有相同的指针值245b4bdc"?
目前,我发现@245b4bdc 不是对象引用",所以 HandleMetaClass@245b4bdc 不一定与 MetaClassImpl@245b4bdc 是同一个实例.我们可以使用 Object.is() 方法来判断它们是否相同.(我这样做了,结果是false)
Currently, I figured out that @245b4bdc is not the "Object reference", So HandleMetaClass@245b4bdc is not necessarily the same instance as MetaClassImpl@245b4bdc. We can use Object.is() method to judge whether they are the same.(I did that, result is false)
推荐答案
为什么 this.metaClass != instance.metaClass?
why this.metaClass != instance.metaClass?
它涉及到groove对字段的访问.
It involves groove's access to fields.
当从外部"访问实例字段时,groovy 实际上调用了函数 getFieldName().在我的例子中,当我使用实例"时,我在外面;所以 instance.metaClass 会调用 instance.getMetaClass().
When accessing an instance field from "outside", groovy actually calls the function getFieldName(). In my example, when I use "instance", i am at the outside; So instance.metaClass will call instance.getMetaClass().
从inside"访问实例字段时,groovy 只是直接访问该字段,不会调用 getFieldName().在我们的例子中,当我使用this"时,我在inside";所以this.metaClass"将直接访问metaClass".
When accessing an instance field from "inside", groovy simply directly access the field, getFieldName() is not called. In our example, when I use "this", i am at the "inside"; So "this.metaClass" will access "metaClass" directly.
最后,getMetaClass() 返回一个 HandleMetaClass 对象,而内部元类是一个 MetaClassImpl 对象.所以this.metaClass!=instance.metaClass.
Finally, getMetaClass() returns a HandleMetaClass object while the internal metaClass is a MetaClassImpl object. So this.metaClass!=instance.metaClass.
为什么 this.metaClass.say={->println "say"} 会抛出 MissingPropertyException?
Why this.metaClass.say={->println "say"} will throws MissingPropertyException?
this.metaClass 的类型是 MetaClassImpl
this.metaClass's type is MetaClassImpl
MetaClassImpl 是一个低级类,它支持用于注入的上级类(例如 HandleMetaClass).不适合Developer直接使用,所以不支持注入方式:xxxx.say={->println "say"}.
MetaClassImpl is a low level class, which supports upper level classes(eg. HandleMetaClass) for injection. It's not meant for Developer to use directly, So it does not support the injection way: xxxx.say={->println "say"}.
代码示例(针对问题 1):
Code Sample(For Question 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:
${this.metaClass}"
println "instance.metaClass:
${instance.metaClass}"
//output: false
println "this.metaClass.is(instance.metaClass):
${this.metaClass.is(instance.metaClass)}"
//output: true
println "this.getMetaClass().is(instance.getMetaClass()):
${this.getMetaClass().is(instance.getMetaClass())}"
}else{
println "no such method:${name}() in Person class"
}
}
}
def jack=new Person()
jack.football()
jack.football()
代码示例(对于问题 2):
Code Sample(For Question 2):
class Cat{}
def a=new groovy.lang.MetaClassImpl(Cat)
try{
a.say={->println "say"}
}catch(MissingPropertyException e){
println "[Fail]
can not inject method say() into MetaClassImpl class.
"
}
def b=new org.codehaus.groovy.runtime.HandleMetaClass(a)
println b
b.say={->println "[say]"}
println "[OK]
can inject method say() into HandleMetaClass class
"
def method=b.getMetaMethod("say")
method.invoke(this)
这篇关于Groovy:this.metaClass 与 instance.metaClass的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!