2012-09-21 65 views
9

我有點困惑groovys方法重載行爲的意外行爲:由於類 和下面的測試中,我與testAStringNulltestBStringNull 拋出曖昧的方法調用異常漂亮沒關係,但爲什麼是不是這樣的爲 testANulltestBNull然後呢?與重載方法

而且,更重要的是:爲什麼testBNull(null) 請致電String foo(A arg)?我猜這個對象不知道它所綁定的變量的類型,但爲什麼這個調用在其他調用時不會含糊其辭?

(我希望我解釋說不夠好,我的頭從產生這個最小 例子傷害。)

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

} 

回答

20

這是Groovy的的(有點鮮爲人知的)怪胎多調度機制,它試圖調用「最合適的」方法,並結合提供的靜態類型(在你的情況下是A或B)不作爲調度機制的一部分。當你聲明A a = null時,你得到的不是A類型的空引用,而是對NullObject的引用。

最終,安全地處理可能爲null參數重載方法,調用者必須在

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

這個討論投的說法,作爲"Groovy Isn't A Superset of Java"可以擺脫對這個問題的一些情況。

+0

很好的答案。嘿,是不是有關於這個「最近階級的路徑」的東西? – Will

+0

你如何寫一個除了null而不使用「a作爲A」的方法?我不想得到一個模棱兩可的方法的例外。 –