Groovy:this.metaClass 对比 instance.metaClass
Groovy: this.metaClass Versus instance.metaClass
我在书中遇到了以下 groovy 脚本代码。它为我生成了一些奇怪的输出。
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[class Person]]"是什么意思?我知道“245b4bdc”可能是对象指针。但是为什么HandleMetaClass和MetaClassImpl有相同的指针值“245b4bdc”呢?
目前,我发现@245b4bdc 不是“对象引用”,所以HandleMetaClass@245b4bdc 不一定相同实例为 MetaClassImpl@245b4bdc。我们可以用Object.is()方法来判断它们是否相同。(我这样做了,结果是false)
为什么 this.metaClass != instance.metaClass?
涉及groove对字段的访问。
从“外部”访问实例字段时,groovy实际上调用了函数getFieldName()。在我的示例中,当我使用“instance”时,我在 outside;所以 instance.metaClass 会调用 instance.getMetaClass().
从“inside”访问实例字段时,groovy只是直接访问该字段,不会调用getFieldName()。在我们的示例中,当我使用“this”时,我在“inside”;所以“this.metaClass”将直接访问“metaClass”。
最后,getMetaClass() returns一个HandleMetaClass对象,而内部元类是一个MetaClassImpl目的。所以this.metaClass!=instance.metaClass.
为什么 this.metaClass.say={->println "say"} 会抛出 MissingPropertyException?
this.metaClass的类型是MetaClassImpl
MetaClassImpl是底层class,支持上层classes(eg. 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)
我在书中遇到了以下 groovy 脚本代码。它为我生成了一些奇怪的输出。
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[class Person]]"是什么意思?我知道“245b4bdc”可能是对象指针。但是为什么HandleMetaClass和MetaClassImpl有相同的指针值“245b4bdc”呢?
目前,我发现@245b4bdc 不是“对象引用”,所以HandleMetaClass@245b4bdc 不一定相同实例为 MetaClassImpl@245b4bdc。我们可以用Object.is()方法来判断它们是否相同。(我这样做了,结果是false)
为什么 this.metaClass != instance.metaClass?
涉及groove对字段的访问。
从“外部”访问实例字段时,groovy实际上调用了函数getFieldName()。在我的示例中,当我使用“instance”时,我在 outside;所以 instance.metaClass 会调用 instance.getMetaClass().
从“inside”访问实例字段时,groovy只是直接访问该字段,不会调用getFieldName()。在我们的示例中,当我使用“this”时,我在“inside”;所以“this.metaClass”将直接访问“metaClass”。
最后,getMetaClass() returns一个HandleMetaClass对象,而内部元类是一个MetaClassImpl目的。所以this.metaClass!=instance.metaClass.
为什么 this.metaClass.say={->println "say"} 会抛出 MissingPropertyException?
this.metaClass的类型是MetaClassImpl
MetaClassImpl是底层class,支持上层classes(eg. 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)