9

私は groovys メソッドのオーバーロード動作について少し混乱しています: 以下のクラスとテストを考えると、あいまいなメソッド呼び出しの例外testAStringNullをスローしても問題ありませんが、 and thentestBStringNull の場合はそうではないのはなぜ ですか?testANulltestBNull

そして、もっと重要なこと: なぜ をtestBNull(null) 呼び出すのString foo(A arg)ですか? オブジェクトはそれがバインドされている変数の型を認識していないと思いますが、他の呼び出しが groovy であっても、その呼び出しがあいまいでないのはなぜですか?

(十分に説明したと思いますが、この最小限の例を生成するのに頭が痛いです。)

class Foo {
    static class A {}
    static class B {}

    String foo(A arg) { return 'a' }

    String foo(String s, A a) { return 'a' }

    String foo(B arg) { return 'b' }

    String foo(String s, B b) { return 'b' }
}

テスト:

import org.junit.Test
import Foo.A
import Foo.B

class FooTest {
    Foo foo = new Foo()

    @Test
    void testA() {
        A a = new A()
        assert foo.foo(a) == 'a'
    }

    @Test
    void testAString() {
        A a = new A()
        assert foo.foo('foo', a) == 'a'
    }

    @Test()
    void testANull() {
        A a = null
        assert foo.foo(a) == 'a'
    }

    @Test
    void testAStringNull() {
        A a = null
        assert foo.foo('foo', a) == 'a'
    }

    @Test
    void testB() {
        B b = new B()
        assert foo.foo(b) == 'b'
    }

    @Test
    void testBString() {
        B b = new B()
        assert foo.foo('foo', b) == 'b'
    }

    @Test
    void testBNull() {
        B b = null
        assert foo.foo(b) == 'b'
    }

    @Test
    void testBStringNull() {
        B b = null
        assert foo.foo('foo', b) == 'b'
    }

}
4

1 に答える 1

21

これは、Groovy のマルチディスパッチ メカニズムの (あまり知られていない) 奇妙さです。これは、提供された静的型 (この場合は A または B) が使用されていないという事実と組み合わせて、「最も適切な」メソッドを呼び出そうとします。発送メカニズムの一部。A a = null を宣言すると、型 A の null 参照ではなく、NullObject への参照が得られます。

最終的に、null の可能性があるパラメーターをオーバーロードされたメソッドに安全に処理するには、呼び出し元が次のように引数をキャストする必要があります。

A a = null
assert foo.foo('foo', a as A) == 'a'

「Groovy は Java のスーパーセットではない」に関するこの議論は、この問題に光を当てるかもしれません。

于 2012-09-21T18:04:04.040 に答える