Respostas:
O problema é que, quando você usa o nulo literal, o Java não sabe que tipo deve ser. Pode ser um objeto nulo ou pode ser uma matriz de objeto nula. Para um único argumento, ele assume o último.
Você tem duas opções. Converta o nulo explicitamente em Object ou chame o método usando uma variável fortemente tipada. Veja o exemplo abaixo:
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));
}
}
Resultado:
foo called, args: [a, b, c]
foo called, args: [null, null]
foo called, args: [null]
foo called, args: [null]
asList()
é uma importação estática da java.util.Arrays
classe. Eu apenas presumi que fosse óbvio. Embora agora que estou pensando sobre isso, eu provavelmente deveria ter apenas usado, Arrays.toString()
pois o único motivo pelo qual ele foi convertido em uma lista é para que tenha uma impressão bonita.
Você precisa de um elenco explícito para Object
:
foo((Object) null);
Caso contrário, o argumento é assumido como todo o array que o varargs representa.
Um caso de teste para ilustrar isso:
O código Java com uma declaração de método vararg-taking (que por acaso é estática):
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 (um caso de teste JUnit4) chama o acima (estamos usando o caso de teste não para testar nada, apenas para gerar alguma saída):
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"}));
}
}
Executá-lo como um teste JUnit produz:
sendNothing (): 'x' recebido é uma matriz de tamanho 0 sendNullWithNoCast (): 'x' recebido é nulo sendNullWithCastToString (): 'x' recebido é uma matriz de tamanho 1 sendNullWithCastToArray (): 'x' recebido é nulo sendOneValue (): recebido 'x' é uma matriz de tamanho 1 sendThreeValues (): recebido 'x' é uma matriz de tamanho 3 sendArray (): o 'x' recebido é um array de tamanho 3
Para tornar isso mais interessante, vamos chamar a receive()
função do Groovy 2.1.2 e ver o que acontece. Acontece que os resultados não são os mesmos! Isso pode ser um bug.
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"
}
}
Executar isso como um teste JUnit produz o seguinte, com a diferença para Java destacada em negrito.
sendNothing (): 'x' recebido é uma matriz de tamanho 0 sendNullWithNoCast (): 'x' recebido é nulo sendNullWithCastToString (): 'x' recebido é nulo sendNullWithCastToArray (): 'x' recebido é nulo sendOneValue (): recebido 'x' é uma matriz de tamanho 1 sendThreeValues (): recebido 'x' é uma matriz de tamanho 3 sendArray (): o 'x' recebido é um array de tamanho 3
eu prefiro
foo(new Object[0]);
para evitar exceções de ponteiro nulo.
Espero que ajude.
foo()
?
A ordem para resolução de sobrecarga de método é ( https://docs.oracle.com/javase/specs/jls/se11/html/jls-15.html#jls-15.12.2 ):
A primeira fase executa a resolução de sobrecarga sem permitir a conversão de boxing ou unboxing, ou o uso de invocação de método de aridade variável. Se nenhum método aplicável for encontrado durante esta fase, o processamento continua para a segunda fase.
Isso garante que quaisquer chamadas que eram válidas na linguagem de programação Java antes do Java SE 5.0 não sejam consideradas ambíguas como resultado da introdução de métodos de aridade variável, boxing e / ou unboxing implícito. No entanto, a declaração de um método de aridade variável (§8.4.1) pode alterar o método escolhido para uma dada expressão de invocação de método de método, porque um método de aridade variável é tratado como um método de aridade fixa na primeira fase. Por exemplo, declarar m (Object ...) em uma classe que já declara m (Object) faz com que m (Object) não seja mais escolhido para algumas expressões de invocação (como m (null)), como m (Object [] ) é mais específico.
A segunda fase executa a resolução de sobrecarga enquanto permite boxing e unboxing, mas ainda impede o uso de invocação de método de aridade variável. Se nenhum método aplicável for encontrado durante esta fase, o processamento continua para a terceira fase.
Isso garante que um método nunca seja escolhido por meio de invocação de método de aridade variável se for aplicável por meio de invocação de método de aridade fixa.
A terceira fase permite que a sobrecarga seja combinada com métodos de aridade variável, boxing e unboxing.
foo(null)
coincide foo(Object... arg)
com arg = null
na primeira fase. arg[0] = null
seria a terceira fase, o que nunca acontece.
asList
método na amostra e sua finalidade.