重载方法的意外行为

c08*_*089 9 groovy

我有点困惑groovys方法重载行为:由于阶级和下面的测试中,我与漂亮没关系testAStringNull,并testBStringNull 抛出暧昧的方法调用例外,但为什么就是不适合的情况 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' }
}
Run Code Online (Sandbox Code Playgroud)

测试:

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'
    }

}
Run Code Online (Sandbox Code Playgroud)

Gre*_*eek 21

这是一个(有点鲜为人知)Groovy的多调度机制的奇怪之处,它试图调用"最合适的"方法,并结合提供的静态类型(在你的情况下为A或B)不被用作调度机制的一部分.当您声明A a = null时,您获得的不是类型A的空引用,而是对NullObject的引用.

最终,为了安全地处理可能为重载方法的null参数,调用者必须转换参数,如

A a = null
assert foo.foo('foo', a as A) == 'a'
Run Code Online (Sandbox Code Playgroud)

关于"Groovy不是Java的超集"的讨论可能会对这个问题有所启发.