Groovy调用运算符在类字段上使用时引发MissingMethodException

时间:2018-08-07 12:42:08

标签: groovy

我正在尝试使用调用运算符()重载,但是它不适用于类字段。怎么了?

class Foo {
    void call(int x){
        println("x="+x)
    }
}

class MyCallable {
    Foo foo = new Foo()
}

Foo foo = new Foo() 
foo(5)  //works

MyCallable mc = new MyCallable()
mc.foo(2) //not works

但是程序因异常终止:

Exception in thread "main" groovy.lang.MissingMethodException: No
signature of method: mpctests.MyCallable.foo() is applicable for
argument types: (java.lang.Integer) values: [2]

1 个答案:

答案 0 :(得分:1)

调用MissingMethodException会得到mc.foo(5),因为Groovy的invoke object方法机制被触发了。有一件事情值得解释,以便更好地了解这种情况。您的MyCallable类:

class MyCallable {
    Foo foo = new Foo()
}

被编译成这样:

import groovy.lang.GroovyObject;
import groovy.lang.MetaClass;
import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
import org.codehaus.groovy.runtime.callsite.CallSite;

public class MyCallable implements GroovyObject {
    private Foo foo;

    public MyCallable() {
        CallSite[] var1 = $getCallSiteArray();
        Object var2 = var1[0].callConstructor(Foo.class);
        this.foo = (Foo)ScriptBytecodeAdapter.castToType(var2, Foo.class);
        MetaClass var3 = this.$getStaticMetaClass();
        this.metaClass = var3;
    }

    public Foo getFoo() {
        return this.foo;
    }

    public void setFoo(Foo var1) {
        this.foo = var1;
    }
}

Groovy还将mc.foo之类的每个字段访问编译为一个getter方法调用mc.getFoo()。因此,当您调用mc.foo(5)时,对于Groovy运行时很明显,您希望在foo(5)对象上调用mc方法。而且此方法不存在,并且会抛出MissingMethodException

但是,如果您创建对象def foo = new Foo()然后调用foo(5),它就可以工作,因为foo是对象,而foo(5)是调用{{1 call(5)对象上的}}方法(foofoo(5)的简写版本)。如果您调用foo.call(5),则会发生相同的情况-Groovy会尝试调用mc()方法。但是当您说出mc.call()时,很明显您正在尝试调用mc.foo(5)方法。


如果您想在foo(5)字段上使用呼叫运算符,则有两种选择:

1。使用直接字段访问运算符mc.foo

@

在这种情况下,您可以直接引用mc.@foo(5) 字段,并且可以使用简写呼叫运算符。

2。使用foo方法

with {}

在这种情况下,对于Groovy运行时来说,访问mc.with { foo(5) } 字段也是很简单的,并且可以在其上使用调用运算符。

替代项

使用getter方法:

foo

直接使用方法mc.getFoo()(5)

call()