¿Cómo se elige un método sobrecargado cuando un parámetro es el valor literal nulo?

Me encontré con esta pregunta en una prueba,

public class MoneyCalc { public void method(Object o) { System.out.println("Object Verion"); } public void method(String s) { System.out.println("String Version"); } public static void main(String args[]) { MoneyCalc question = new MoneyCalc(); question.method(null); } } 

El resultado de este progtwig es “Versión de cadena”. Pero no pude entender por qué al pasar un valor nulo a un método sobrecargado elegí la versión de cadena. ¿Es nula una variable String que apunta a nada?

Sin embargo, cuando se cambia el código a,

 public class MoneyCalc { public void method(StringBuffer sb) { System.out.println("StringBuffer Verion"); } public void method(String s) { System.out.println("String Version"); } public static void main(String args[]) { MoneyCalc question = new MoneyCalc(); question.method(null); } } 

da un error de comstackción que dice “El método método (StringBuffer) es ambiguo para el tipo MoneyCalc”

¿Es nula una variable String que apunta a nada?

Una referencia nula se puede convertir a una expresión de cualquier tipo de clase. Entonces en el caso de String , esto está bien:

 String x = null; 

La sobrecarga de String aquí se elige porque el comstackdor de Java selecciona la sobrecarga más específica , según la sección 15.12.2.5 del JLS . En particular:

La intuición informal es que un método es más específico que otro si cualquier invocación manejada por el primer método podría pasarse a la otra sin un error de tipo de tiempo de comstackción.

En su segundo caso, ambos métodos siguen siendo aplicables, pero ni String ni StringBuffer son más específicos que el otro, por lo tanto, ninguno de los métodos es más específico que el otro, de ahí el error del comstackdor.

Además, el JLS 3.10.7 también declara que “nulo” es un valor literal del “tipo nulo”. Por lo tanto, existe un tipo llamado “nulo”.

Más tarde, el JLS 4.1 establece que existe un tipo nulo del cual es imposible declarar variables, pero puede usarlo solo a través del literal nulo. Más tarde dice:

La referencia nula siempre puede sufrir una conversión de referencia de ampliación a cualquier tipo de referencia.

Por qué el comstackdor elige ensancharlo a String bien podría explicarse en la respuesta de Jon .

Puede asignar una string a un valor null , por lo que es válida y el orden para Java y la mayoría de los lenguajes de progtwigción se ajusta al tipo más cercano y luego al objeto.

Para responder la pregunta en el título: null no es una String ni un Object , pero una referencia a cualquiera de ellos se puede asignar a null .

De hecho, me sorprende que este código incluso comstack. Intenté algo similar anteriormente y obtuve un error de comstackción que decía que la llamada era ambigua.

Sin embargo, en este caso, parece que el comstackdor elige el método más bajo en la cadena alimentaria. Se asume que desea la versión menos genérica del método para ayudarlo.

Tendré que ver si puedo desenterrar el ejemplo donde obtuve un error de comstackción en este (aparentemente) mismo escenario exacto, aunque …]

EDITAR: Ya veo. En la versión que hice, tenía dos métodos sobrecargados que aceptaban un String y un Integer . En este escenario, no existe el parámetro “más específico” (como en Object y String ), por lo que no puede elegir entre ellos, a diferencia de su código.

Muy buena pregunta!

Como tipo de cadena es más específico que el tipo de objeto. Digamos que agrega un método más que toma un tipo entero.

 public void method(Integer i) { System.out.println("Integer Version"); } 

Luego obtendrá un error de comstackción que dice que la llamada es ambigua. Como ahora tenemos dos métodos igualmente específicos con la misma precedencia.

El comstackdor de Java proporciona la mayoría del tipo de clase derivada para asignar null.

Aquí está el ejemplo para entenderlo:

 class A{ public void methodA(){ System.out.println("Hello methodA"); } } class B extends A{ public void methodB(){ System.out.println("Hello methodB"); } } class C{ public void methodC(){ System.out.println("Hello methodC"); } } public class MyTest { public static void fun(B Obj){ System.out.println("B Class."); } public static void fun(A Obj){ System.out.println("A Class."); } public static void main(String[] args) { fun(null); } } 

salida: Clase B

por otra parte:

 public class MyTest { public static void fun(C Obj){ System.out.println("B Class."); } public static void fun(A Obj){ System.out.println("A Class."); } public static void main(String[] args) { fun(null); } } 

Resultado: el método fun (C) es ambiguo para el tipo MyTest

Espero que ayude a entender mejor este caso.

Yo diría que ninguno. NULL es un estado, no un valor. Consulte este enlace para obtener más información al respecto (el artículo se aplica a SQL, pero creo que también ayuda con su pregunta).