代码之家  ›  专栏  ›  技术社区  ›  chabapok

Groovy调用运算符在用于类字段时抛出MissingMethodException

  •  1
  • chabapok  · 技术社区  · 6 年前

    我想用电话接线员 () 重载,但它不适用于类字段。发生了什么?

    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 回复  |  直到 6 年前
        1
  •  1
  •   Szymon Stepniak    6 年前

    你得到 MissingMethodException 当你打电话 mc.foo(5) ,因为Groovy的调用对象方法机制被触发。有一件事值得解释,以便更好地了解这种情况。你的 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(五) 很明显,对于Groovy运行时,您希望调用 foo(5) 方法打开 mc 反对。这种方法不存在 MissingMethodException 被扔了。

    但是,如果创建对象 def foo = new Foo() 然后你打电话 福(5) ,因为 foo 是一个物体 福(5) 是调用的严格指令 call(5) 方法打开 对象( 福(5) foo.call(5) ). 如果你打电话给 mc() -Groovy会尝试调用 mc.call() 方法。但是当你说 mc.foo(五) 很明显你想 福(5) 方法。


    如果您想使用呼叫接线员 美孚 字段有两个选项:

    一。使用直接字段访问运算符 @

    mc.@foo(5)
    

    在这种情况下,您可以直接引用 字段,您可以使用速记呼叫接线员。

    2。使用 with {} 方法

    mc.with {
        foo(5)
    }
    

    在本例中,对于Groovy运行时,访问 你可以用电话接线员。

    选择

    使用getter方法:

    mc.getFoo()(5)
    

    使用方法 call() 直接:

    mc.foo.call(5) // equivalent of mc.getFoo().call(5)