varargs vararg argumentos null language-design java variadic-functions

null - argumentos - ¿Llamar al método varargs de Java con un solo argumento nulo?



vararg kotlin (5)

Si tengo un método vararg Java foo(Object ...arg) y llamo foo(null, null) , tengo ambos arg[0] y arg[1] como null s. Pero si llamo a foo(null) , arg sí es nulo. ¿Por qué está pasando esto?

¿Cómo debo llamar a foo para que foo.length == 1 && foo[0] == null sea true ?


El problema es que cuando usas el literal nulo, Java no sabe qué tipo se supone que es. Podría ser un Objeto nulo, o podría ser una matriz de Objeto nulo. Para un argumento único, asume lo segundo.

Tienes dos opciones. Emitir el nulo explícitamente a Object o llamar al método usando una variable fuertemente tipada. Vea el ejemplo a continuación:

public class Temp{ public static void main(String[] args){ foo("a", "b", "c"); foo(null, null); foo((Object)null); Object bar = null; foo(bar); } private static void foo(Object...args) { System.out.println("foo called, args: " + asList(args)); } }

Salida:

foo called, args: [a, b, c] foo called, args: [null, null] foo called, args: [null] foo called, args: [null]


Esto se debe a que se puede invocar un método varargs con una matriz real en lugar de una serie de elementos de matriz. Cuando le proporciona el null ambiguo por sí mismo, asume que el null es un Object[] . Lanzar el null a Object arreglará esto.


Necesitas un elenco explícito para Object :

foo((Object) null);

De lo contrario, se supone que el argumento es la matriz completa que representan los varargs.


Un caso de prueba para ilustrar esto:

El código de Java con una declaración de método vararg-taking (que pasa a ser estático):

public class JavaReceiver { public static String receive(String... x) { String res = ((x == null) ? "null" : ("an array of size " + x.length)); return "received ''x'' is " + res; } }

Este código Java (un caso de prueba JUnit4) llama a lo anterior (estamos utilizando el caso de prueba para no probar nada, solo para generar algún resultado):

import org.junit.Test; public class JavaSender { @Test public void sendNothing() { System.out.println("sendNothing(): " + JavaReceiver.receive()); } @Test public void sendNullWithNoCast() { System.out.println("sendNullWithNoCast(): " + JavaReceiver.receive(null)); } @Test public void sendNullWithCastToString() { System.out.println("sendNullWithCastToString(): " + JavaReceiver.receive((String)null)); } @Test public void sendNullWithCastToArray() { System.out.println("sendNullWithCastToArray(): " + JavaReceiver.receive((String[])null)); } @Test public void sendOneValue() { System.out.println("sendOneValue(): " + JavaReceiver.receive("a")); } @Test public void sendThreeValues() { System.out.println("sendThreeValues(): " + JavaReceiver.receive("a", "b", "c")); } @Test public void sendArray() { System.out.println("sendArray(): " + JavaReceiver.receive(new String[]{"a", "b", "c"})); } }

Ejecutando esto como una prueba JUnit produce:

sendNothing(): received ''x'' is an array of size 0 sendNullWithNoCast(): received ''x'' is null sendNullWithCastToString(): received ''x'' is an array of size 1 sendNullWithCastToArray(): received ''x'' is null sendOneValue(): received ''x'' is an array of size 1 sendThreeValues(): received ''x'' is an array of size 3 sendArray(): received ''x'' is an array of size 3

Para que esto sea más interesante, llamemos a la función receive() de Groovy 2.1.2 y veamos qué sucede. ¡Resulta que los resultados no son los mismos! Aunque esto puede ser un error.

import org.junit.Test class GroovySender { @Test void sendNothing() { System.out << "sendNothing(): " << JavaReceiver.receive() << "/n" } @Test void sendNullWithNoCast() { System.out << "sendNullWithNoCast(): " << JavaReceiver.receive(null) << "/n" } @Test void sendNullWithCastToString() { System.out << "sendNullWithCastToString(): " << JavaReceiver.receive((String)null) << "/n" } @Test void sendNullWithCastToArray() { System.out << "sendNullWithCastToArray(): " << JavaReceiver.receive((String[])null) << "/n" } @Test void sendOneValue() { System.out << "sendOneValue(): " + JavaReceiver.receive("a") << "/n" } @Test void sendThreeValues() { System.out << "sendThreeValues(): " + JavaReceiver.receive("a", "b", "c") << "/n" } @Test void sendArray() { System.out << "sendArray(): " + JavaReceiver.receive( ["a", "b", "c"] as String[] ) << "/n" } }

Ejecutar esto como una prueba JUnit produce lo siguiente, con la diferencia de que Java se resalta en negrita.

sendNothing(): received ''x'' is an array of size 0 sendNullWithNoCast(): received ''x'' is null sendNullWithCastToString(): received ''x'' is null sendNullWithCastToArray(): received ''x'' is null sendOneValue(): received ''x'' is an array of size 1 sendThreeValues(): received ''x'' is an array of size 3 sendArray(): received ''x'' is an array of size 3


yo prefiero

foo(new Object[0]);

para evitar excepciones del puntero nulo.

Espero eso ayude.