我在书中遇到了下面的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
所以我很困惑:
目前,我发现@245b4bdc不是“HandleMetaClass@245b4bdc对象引用”,所以MetaClassImpl@245b4bdc.不一定是同一个实例。我们可以使用Object.is()方法来判断它们是否相同。(我这样做了,结果是false)
发布于 2015-12-25 04:52:38
- 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()**.
- 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.
- Finally, getMetaClass() returns a **HandleMetaClass** object while the internal metaClass is a **MetaClassImpl** object. So **this.metaClass!=instance.metaClass**.
- this.metaClass's type is MetaClassImpl
- 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):
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)
https://stackoverflow.com/questions/34449587
复制