【问题标题】:What is Groovy doing here?Groovy 在这里做什么?
【发布时间】:2012-03-20 11:43:45
【问题描述】:

我试图调试一些使用 mixins 的代码,并且我能够将我的问题简化为这个示例。我有一个通过 mixin 接收方法的父类和一个从父类继承的子类。如果我尝试替换子类实例上的方法,它会起作用除非,我要替换的方法在父类实例被替换之前被调用。如果它已被调用,那么我无法替换它

所以这段代码:

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

【问题讨论】:

  • 我也可以在 Groovy 1.8.4 中重现这个。我闻起来像虫子;但我不太喜欢 Groovy 元编程,所以我不知道。
  • 感谢您的说明,如果我最终提交错误,我一定会包括在内。
  • 我会在 groovy 用户邮件列表上问这个问题,对我来说闻起来像一个错误......
  • 这可能与任何方法处理程序缓存有关吗?

标签: inheritance groovy mixins metaclass


【解决方案1】:

metaClass 在方法调用中被查看,mixin 有自己的处理程序。 两者都是延迟加载的,并且是静态的,如果您不调用方法,则不会发生静态延迟加载。
Mixins 优先于 metaClass 覆盖,这就是为什么如果您初始化 A,它会显示 foo 而不会获胜。
元是在它所应用的对象上定义的,以便为每个类解析它,您需要 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

【讨论】:

  • 您有可以引用此信息的来源吗?我不完全听从您的回答,也找不到有关 Groovy 元存储的任何信息。
  • 所有这些都取自文档并自己摆弄控制台。你的问题很有趣,在我看来,它本身就值得一篇博文。文档的 Dynamic Groovy 页面已经提供了一些答案 groovy.codehaus.org/Per-Instance+MetaClass
猜你喜欢
  • 1970-01-01
  • 2011-01-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多