Groovy在这里做什么?

问题描述:

我试图调试一些使用mixin的代码,我能够将我的问题简化为这个例子。我有一个父类,它通过一个mixin和一个从父类继承的子类来接收方法。如果我尝试替换子类的实例上的方法,它将起作用除非我更换的方法在父类的实例被替换之前调用。如果已被称为然后,我不能没有它Groovy在这里做什么?

所以这个代码:

class M { 
    protected foo() { println 'foo' } 
} 

@Mixin(M) class A { 
def bar() { foo() } 
} 

class B extends A {} 

def b = new B() 
def a = new A() 
a.bar() //<-- comment out this line and see the difference 
b.metaClass.foo = {println 'winning'} 
b.bar() 

将产生:

但如果你注释掉第13行(带有评论的评论),你会得到:

获奖

为什么会出现这种情况?我期望在Groovy的元类模型的背景下有一些合理的方法,但我不明白。

这是Groovy的1.8.6

+1

我也可以在Groovy 1.8.4中重现这一点。闻起来像一个臭虫给我;但我并不太在意Groovy元编程,所以我不知道。 – epidemian 2012-03-01 22:55:08

+0

感谢您的注意事项,如果我最终提出了一个错误,我一定会加入。 – mfollett 2012-03-01 23:27:00

+0

我在groovy用户邮件列表上问这个,闻起来像是一个bug ... – 2012-03-01 23:47:35

元类上的方法调用,并混入有自己的处理程序时看。 两者都是延迟加载的,而静态的,如果你不调用一个方法,静态延迟加载不会发生。
Mixins优先于metaClass覆盖,这就是为什么它显示foo并且如果初始化A而不会获胜。
meta定义在它所应用的对象上,以便按需要解析它。Object.class .metaClass(即这里B.metaClass)。 有趣的是这产生了:

groovy.lang.MissingMethodException: No signature of method: B.foo() is applicable for argument types:() values: [] 
Possible solutions: foo(), foo(java.lang.Object), bar(), any(), use([Ljava.lang.Object;), find(groovy.lang.Closure) 

第B定义FOO解决错误:

class B extends A { 
    def foo() { println 'not winning' } 
} 

你的答案是的Mixin影响类metastore,和类方法优先对象metastore方法。

证明:

@Mixin(M) 
class B extends A { 

} 

a.bar() //<-- comment out this line and see the difference 
B.metaClass.foo = {println 'class winning'} 
b.metaClass.foo = {println 'object winning'} 
b.bar() 

产量:

foo 
class winning 

一种不同的方法

class M { 
    protected foo() { println 'foo' } 
} 

@Mixin(M) class A { 
def bar() { foo() } 
} 

class B extends A { 
    def bar() { foo() } 
} 

class C extends B { 
    def foo() { println 'wat' } 
} 

@Mixin(M) 
class D extends C { } 

def b = new B() 
def a = new A() 
def c = new C() 
def d = new D() 


a.bar() //<-- comment out this line and see the difference 
b.metaClass.foo = {println 'winning'} 
b.bar() 

c.metaClass.foo = {println 'losing'} 
c.bar() 

d.metaClass.foo = {println 'draw'} 
d.bar() 

息率

foo 
winning 
wat 
wat 
+0

你有来源可以引用此信息吗?我不完全按照你的回答,也找不到有关Groovy的metastore的信息。 – mfollett 2012-04-03 22:43:05

+0

所有这一切都来自文档,并自己控制台。在我看来,你的问题非常有趣,值得一读博客文章。文档的Dynamic Groovy页面已经提供了一些答案http://groovy.codehaus.org/Per-Instance+MetaClass – Gepsens 2012-04-08 09:33:12