我无法理解GroovyClassLoader缓存如何与expando方法一起使用。
特别是,我希望下面的代码为每次调用Number.test()提供不同的输出,但事实并非如此。
int i = 1
Number.metaClass.test = {
return "A string"
}
println i.test()
println GroovySystem.metaClassRegistry.getMetaClass(Number.class)
Number.metaClass = null
println GroovySystem.metaClassRegistry.getMetaClass(Number.class)
Number.metaClass.test = {
return "Another String"
}
println i.test()
println GroovySystem.metaClassRegistry.getMetaClass(Number.class)
GroovySystem.metaClassRegistry.removeMetaClass(Number.class)
println GroovySystem.metaClassRegistry.getMetaClass(Number.class)
Number.metaClass.test = {
return "Yet another String"
}
println i.test()
输出:
A string
groovy.lang.ExpandoMetaClass@3571b748[class java.lang.Number]
groovy.lang.MetaClassImpl@7748410a[class java.lang.Number]
A string
groovy.lang.ExpandoMetaClass@37f1104d[class java.lang.Number]
groovy.lang.MetaClassImpl@55740540[class java.lang.Number]
A string
修改
我尝试了更多的东西。看起来我的系统表现得非常奇怪。给出以下代码:
def i = 1
i.class
Number.metaClass.test = {
return "A string"
}
println i.test()
Number.metaClass = null
Number.metaClass.test = {
return "Another String"
}
println i.test()
GroovySystem.metaClassRegistry.removeMetaClass(Number.class)
Number.metaClass.test = {
return "Yet another String"
}
println i.test()
当我在我的系统上执行它时,它按预期工作(在输出中获得3个不同的字符串)但如果我评论所谓无用的A string
,则它会失败(3 x i.class
)。
但是,如果我在groovy-console.appspot.com上执行它,它会给我带有或不带该行的预期输出......
我有点不知所措。
答案 0 :(得分:1)
创建int i = 9
时,它创建了一个包含当前Number.metaClass
的对象。它接受创建一个新方法(读Number.metaClass.test = { "A string" }
),但不允许重载已存在的方法。您可以改为改变对象的元类:
int i = 1
Number.metaClass.test = { "A string" }
assert i.test() == "A string"
Number.metaClass = null
i.metaClass.test = { "Another String" }
assert i.test() == "Another String"
GroovySystem.metaClassRegistry.removeMetaClass(Number.class)
assert i.test() == "Another String"
i.metaClass.test = { "Yet another String" }
assert i.test() == "Yet another String"
需要调用i.class
对我来说看起来像个错误...看看jira我看到了一些未解决的问题和打开的错误。我认为你的看起来与这些相似:
在更改实例metaClass之前,Java类metaClass上的覆盖方法不会生效:https://issues.apache.org/jira/browse/GROOVY-5065
使用metaClass覆盖类层次结构中的方法不能按预期工作:https://issues.apache.org/jira/browse/GROOVY-3942
通过.metaClass重写方法的行为不一致:https://issues.apache.org/jira/browse/GROOVY-6847
删除metaClass方法:https://issues.apache.org/jira/browse/GROOVY-4189
如果你考虑一个具体的课程,我的答案的第一部分是有效的:
class Echo {}
Echo.metaClass.test = { "A string" }
def i = new Echo()
assert i.test() == "A string"
Echo.metaClass = null
Echo.metaClass.test = { "Another String" }
assert i.test() == "A string"
i.metaClass.test = { "Another String" }
assert i.test() == "Another String"
i.metaClass.test = { "Yet another String" }
assert i.test() == "Yet another String"