Respuestas:
El problema es que cuando usa el nulo literal, Java no sabe qué tipo se supone que es. Podría ser un objeto nulo o podría ser una matriz de objetos nula. Para un solo argumento, asume lo último.
Tienes dos opciones. Convierta el nulo explícitamente en Object o llame al método utilizando 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]
asList()
es una importación estática de la java.util.Arrays
clase. Simplemente asumí que era obvio. Aunque ahora que lo estoy pensando, probablemente debería haberlo usado, Arrays.toString()
ya que la única razón por la que se convierte en una Lista es para que se imprima de forma bonita.
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 Java con una declaración de método de toma de vararg (que resulta 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 usando el caso de prueba no para probar nada, solo para generar alguna salida):
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"}));
}
}
Ejecutar esto como una prueba JUnit produce:
sendNothing (): la 'x' recibida es una matriz de tamaño 0 sendNullWithNoCast (): la 'x' recibida es nula sendNullWithCastToString (): recibida 'x' es una matriz de tamaño 1 sendNullWithCastToArray (): 'x' recibido es nulo sendOneValue (): 'x' recibido es una matriz de tamaño 1 sendThreeValues (): 'x' recibido es una matriz de tamaño 3 sendArray (): la 'x' recibida es una matriz de tamaño 3
Para hacer esto más interesante, llamemos a la receive()
función de Groovy 2.1.2 y veamos qué sucede. ¡Resulta que los resultados no son los mismos! Sin embargo, 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 con Java resaltada en negrita.
sendNothing (): la 'x' recibida es una matriz de tamaño 0 sendNullWithNoCast (): la 'x' recibida es nula sendNullWithCastToString (): 'x' recibido es nulo sendNullWithCastToArray (): 'x' recibido es nulo sendOneValue (): 'x' recibido es una matriz de tamaño 1 sendThreeValues (): 'x' recibido es una matriz de tamaño 3 sendArray (): la 'x' recibida es una matriz de tamaño 3
yo prefiero
foo(new Object[0]);
para evitar excepciones de puntero nulo.
Espero eso ayude.
foo()
?
El orden para la resolución de sobrecarga de métodos es ( https://docs.oracle.com/javase/specs/jls/se11/html/jls-15.html#jls-15.12.2 ):
La primera fase realiza la resolución de sobrecarga sin permitir la conversión de boxeo o unboxing, o el uso de la invocación del método de aridad variable. Si no se encuentra ningún método aplicable durante esta fase, el procesamiento continúa a la segunda fase.
Esto garantiza que las llamadas que eran válidas en el lenguaje de programación Java antes de Java SE 5.0 no se consideran ambiguas como resultado de la introducción de métodos de aridad variable, boxing implícito y / o unboxing. Sin embargo, la declaración de un método de aridad variable (§8.4.1) puede cambiar el método elegido para una expresión de invocación de método de método dada, porque un método de aridad variable se trata como un método de aridad fija en la primera fase. Por ejemplo, declarar m (Objeto ...) en una clase que ya declara m (Objeto) hace que m (Objeto) ya no se elija para algunas expresiones de invocación (como m (nulo)), como m (Objeto [] ) es más específico.
La segunda fase realiza la resolución de la sobrecarga al tiempo que permite el boxeo y el desempaquetado, pero aún excluye el uso de la invocación del método de aridad variable. Si no se encuentra ningún método aplicable durante esta fase, el procesamiento continúa hasta la tercera fase.
Esto asegura que nunca se elija un método mediante la invocación del método de aridad variable si es aplicable a través de la invocación del método de aridad fija.
La tercera fase permite combinar la sobrecarga con métodos de aridad variable, boxeo y unboxing.
foo(null)
coincide foo(Object... arg)
con arg = null
en la primera fase. arg[0] = null
sería la tercera fase, que nunca ocurre.
asList
método en la muestra y su propósito.