Guo*_*eng 8 groovy metaclass 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()
Run Code Online (Sandbox Code Playgroud)
它的输出如下:
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
Run Code Online (Sandbox Code Playgroud)
所以我很困惑:
目前,我发现@ 245b4bdc不是" 对象引用 ",因此HandleMetaClass @ 245b4bdc不一定与MetaClassImpl @ 245b4bdc相同.我们可以使用Object.is()方法来判断它们是否相同.(我这样做,结果是假的)
为什么 this.metaClass != instance.metaClass ?
它涉及groove对字段的访问。
当从“外部”访问实例字段时,groovy 实际上调用函数 getFieldName()。在我的例子中,当我使用“ instance ”时,我在外面;因此,instance.metaClass将调用instance.getMetaClass()。
当从“ inside ”访问实例字段时,groovy 只是直接访问该字段,而不会调用 getFieldName() 。在我们的例子中,当我使用“ this ”时,我在“ inside ”;所以“ this.metaClass ”将直接访问“ 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()
Run Code Online (Sandbox Code Playgroud)
代码示例(针对问题 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)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
687 次 |
| 最近记录: |