2012-09-21 29 views
9

Estoy un poco confundido sobre el comportamiento de la sobrecarga de métodos groovys: Teniendo en cuenta la clase y las pruebas abajo, estoy bastante bien con testAStringNull y testBStringNull lanzar excepciones de llamadas a métodos ambiguos, pero ¿por que no es el caso para testANull y testBNull, entonces?comportamiento inesperado con métodos sobrecargados

Y, mucho más importante: ¿por qué testBNull(null) llama String foo(A arg)? Supongo que el objeto no sabe sobre el tipo de variable a la que está vinculado, pero ¿por qué esa llamada no es ambigua a groovy mientras que las otras sí lo son?

(espero que he explicado lo suficientemente bien, me duele la cabeza de la generación de este mínimo ejemplo.)

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

Pruebas:

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

} 

Respuesta

20

Es una (algo poco conocido) rareza del maravilloso de mecanismo de envío múltiple, que al intentar invocar el método "más apropiado", en combinación con el hecho de que el tipo estático proporcionado (en su caso A o B) no se utiliza como parte del mecanismo de envío. Cuando declaras A a = null, lo que obtienes no es una referencia nula de tipo A, sino una referencia a NullObject.

En última instancia, para manejar con seguridad los parámetros posiblemente nulos a métodos sobrecargados, la persona que llama debe emitir el argumento, como en

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

Esta discusión sobre "Groovy Isn't A Superset of Java" puede arrojar alguna luz sobre el tema.

+0

Buena respuesta. Oye, ¿no hay algo relacionado con un "camino de la clase más cercana" relacionado con esto? – Will

+0

¿Y cómo se escribe un método que excluya el nulo sin usar "a como A"? No quiero obtener una excepción de métodos ambiguos. –

Cuestiones relacionadas