我希望覆盖metaClass上的一个动态属性,但它并没有按照我的预期工作。以下是一个简单的示例,演示了这个问题。你可以在Groovy web console上在线运行它。
class Bike {}
class Bell { def ring() { println("calling " + this) } }
def createNamespaces = {
return [ "bell": new Bell() ]
}
def resetNamespaces = { bike ->
// setting to null means 'set it to the default'
bike.metaClass = null
createNamespaces().each { name, namespace ->
println("setting " + namespace)
bike.metaClass."$name" = namespace
}
}
def bike= new Bike()
resetNamespaces(bike)
bike.bell.ring()
resetNamespaces(bike)
bike.bell.ring()
结果如下:
setting Bell@14e9bd2b
calling Bell@14e9bd2b
setting Bell@948a7ad
calling Bell@14e9bd2b
所以,尽管我已更改了metaClass上的属性,但调用它始终返回设置的第一个对象。是否存在某种缓存机制?
当我将示例的最后一部分更改为以下内容时:
resetNamespaces(bike)
resetNamespaces(bike)
bike.bell.ring()
那么,结果如预期一样。也就是说,调用该属性会返回在metaClass上最后设置的对象:
setting Bell@5b47e0c7
setting Bell@19f373a4
calling Bell@19f373a4
我甚至尝试手动设置metaClass,如下所示。
def resetNamespaces = { bike ->
def newMetaClass = new ExpandoMetaClass(Bike.class, true, true)
newMetaClass.initialize()
bike.metaClass = newMetaClass
...
}
但结果仍然是一样的。因此可能涉及到某种缓存机制。我在文档中找不到任何关于这种行为的说明。