2008-12-18 19 views
12

¿Por qué (aparentemente) a hacer una diferencia acerca de mi aprobación null como argumento directamente, o pasar un Object que le asigna el valor null?Java despacho método con un argumento nulo

Object testVal = null; 
test.foo(testVal); // dispatched to foo(Object) 
// test.foo(null); // compilation problem -> "The method foo(String) is ambiguous" 

public void foo(String arg) { // More-specific 
    System.out.println("foo(String)"); 
} 

public void foo(Object arg) { // Generic 
    System.out.println("foo(Object)"); 
} 

En otras palabras, ¿por qué el (comentado en salir) segunda llamada a foo(...) no envió a foo(Object)?

Actualización: Uso Java 1.6. Pude compilar el código de Hemal sin problemas, pero el mío todavía no compila. La única diferencia que veo es que los métodos de Hemal son estáticos mientras que los míos no. Pero realmente no veo por qué esto debería hacer la diferencia ...?

Actualización 2: Resuelto. Tenía otro método foo (Runnable) en mi clase, por lo que el despachador no pudo seleccionar inequívocamente el método más específico. (Vea mi comentario en la segunda respuesta de Hemal.) Gracias a todos por su ayuda.

Respuesta

24

¿Qué versión de Java estás usando? Con 1.6.0_11, el código (pegado a continuación) se compila y ejecuta.

Estoy seguro de que es obvio por qué foo(testVal) va a foo(Object).

El motivo por el cual foo(null) va a foo(String) es un poco complejo. La constante null es del tipo nulltype, que es un subtipo de todos los tipos. Por lo tanto, este nulltype se extiende String, que se extiende Object.

Cuando llame al foo(null), el compilador busca el método sobrecargado con el tipo más específico. Como String es más específico, entonces Object es el método que se llama.

Si tenía otra sobrecarga que era tan específica como String, digamos foo(Integer), entonces obtendría un error de sobrecarga ambiguo.

class NullType { 

    public static final void main(final String[] args) { 
    foo(); 
    } 

    static void foo() 
    { 
    Object testVal = null; 
    foo(testVal); // dispatched to foo(Object) 
    foo(null); // compilation problem -> "The method foo(String) is ambiguous" 
    } 

    public static void foo(String arg) { // More-specific 
    System.out.println("foo(String)"); 
    } 

    public static void foo(Object arg) { // Generic 
    System.out.println("foo(Object)"); 
    } 

} 
+0

Acabo de probar esto y estoy sorprendido de que (a) 6u11 no dice que es ambiguo, y (b) que nulo se resuelve en Cadena no Objeto. Aprende algo nuevo todos los días: +1 para la lección. –

+1

@Software Monkey: una vez que acepta que la constante nula es de tipo nulo y el tipo nulo es un subtipo de todos los tipos, esto es bastante obvio. Objeto

+0

Pedantería: el método está anulando Objeto con cadena. La sobrecarga es cuando el nombre del método es el mismo, pero la firma varía más ampliamente. Excelente respuesta Gracias. – Sam

2

Porque la segunda invocación comentada con nulo es ambigua para el compilador. El nulo literal podría ser una cadena o un objeto. Mientras que el valor asignado tiene un tipo definido. Debes emitir el nulo, p. test.foo ((String) null) para eliminar la ambigüedad.

1

¿Alguien ha probado el ejemplo ???

Con 1.6.0 foo (nulo) se distribuye para el método más específico aplicable que es foo (cadena) ...

Si se agrega un nuevo método dicen foo (entero) el compilador no puede elegir el más método específico aplicable y muestra un error.

-Patrick

1

Lo sentimos utilizar una respuesta, por un comentario, pero necesito para publicar el código que no se ajuste en el comentario.

@Yang, también puedo compilar y ejecutar lo siguiente. ¿Puedes publicar un código completo que compila con una línea comentada de tal manera que si descomiento esa línea no se compilará?

class NullType { 

    public static final void main(final String[] args) { 
    foo(); 
    new Test().bar(new Test()); 
    } 

    static void foo() 
    { 
    Object testVal = null; 
    foo(testVal); // dispatched to foo(Object) 
    // foo(null); // compilation problem -> "The method foo(String) is ambiguous" 
    } 

    public static void foo(String arg) { // More-specific 
    System.out.println("foo(String)"); 
    } 

    public static void foo(Integer arg) { // More-specific 
    System.out.println("foo(Integer)"); 
    } 

    public static void foo(Object arg) { // Generic 
    System.out.println("foo(Object)"); 
    } 


} 


class Test 
{ 
    void bar(Test test) 
    { 
    Object testVal = null; 
    test.foo(testVal); // dispatched to foo(Object) 
    test.foo(null); // compilation problem -> "The method foo(String) is ambiguous" 
    } 

    public void foo(String arg) { // More-specific 
    System.out.println("foo(String)"); 
    } 

    public void foo(Object arg) { // Generic 
    System.out.println("foo(Object)"); 
    } 
} 
+0

Huh, limpié mi clase de prueba para publicarla aquí y me di cuenta de que además de foo (String) y foo (Object), también tenía un foo (Runnable), que ahora entiendo causó que foo (null) sea ambiguo porque String no es más específico que Runnable, y viceversa. ¡Gracias a Hemal por tu valiosa ayuda! –

+0

Me alegro de haber podido ayudar. De nada. –

Cuestiones relacionadas