2012-09-21 18 views
9

Sono un po 'confuso sul metodo groovys comportamento sovraccarico: data la classe di e le prove di seguito, sono abbastanza d'accordo con testAStringNull e testBStringNull gettando ambigue eccezioni metodo di chiamata, ma perché è che non è il caso per testANull e testBNull quindi?comportamento imprevisto con metodi di overload

E, ancora più importante: perché testBNull(null) chiama String foo(A arg)? Immagino che l'oggetto non sia a conoscenza del tipo di variabile a cui è legato, ma perché questa chiamata non è ambigua da groovy mentre gli altri sono?

(spero ho spiegato abbastanza bene, la mia testa fa male da generare questo minimo esempio.)

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

Test:

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

} 

risposta

20

E 'una (un po' poco noto) stranezza di Groovy di meccanismo multi-dispatch, che come tentativo di invocare il metodo "più appropriato", in combinazione con il fatto che il tipo statico fornito (nel tuo caso A o B) non è usato come parte del meccanismo di invio. Quando si dichiara A a = null, ciò che si ottiene non è un riferimento null di tipo A, ma un riferimento a NullObject.

definitiva, di gestire in modo sicuro parametri eventualmente nulli a metodi di overload, il chiamante deve lanciare l'argomento, come in

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

Questa discussione "Groovy Isn't A Superset of Java" può far luce sulla questione.

+0

Buona risposta. Ehi, non c'è qualcosa riguardo a un "percorso dalla classe più vicina" relativo a questo? – Will

+0

E come si scrive un metodo che esclude nulla senza usare "a as A"? Non voglio ottenere un'eccezione con metodi ambigui. –

Problemi correlati