Jeśli mam metodę vararg Java foo(Object ...arg)
i wywołuję foo(null, null)
, mam obie arg[0]
i arg[1]
jako null
s. Ale jeśli dzwonię foo(null)
, arg
samo w sobie jest zerowe. Dlaczego to się dzieje?
Jak mam nazwać to foo
, co foo.length == 1 && foo[0] == null
jest true
?
null
language-design
java
variadic-functions
pathikrit
źródło
źródło
asList
metodę w próbce i jej cel.asList()
to statyczny import zjava.util.Arrays
klasy. Po prostu założyłem, że to oczywiste. Chociaż teraz, kiedy o tym myślę, prawdopodobnie powinienem był po prostu użyć,Arrays.toString()
ponieważ jedynym powodem, dla którego zostanie przekonwertowany na listę, jest to, że będzie ładnie drukować.Potrzebujesz wyraźnej obsady, aby
Object
:foo((Object) null);
W przeciwnym razie przyjmuje się, że argumentem jest cała tablica, którą reprezentuje varargs.
źródło
Przypadek testowy ilustrujący to:
Kod Javy z deklaracją metody pobierającej vararg (która jest statyczna):
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; } }
Ten kod Java (przypadek testowy JUnit4) wywołuje powyższe (używamy przypadku testowego, aby niczego nie testować, tylko po to, aby wygenerować dane wyjściowe):
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"})); } }
Uruchomienie tego jako testu JUnit daje:
Aby było to bardziej interesujące, wywołajmy
receive()
funkcję z Groovy 2.1.2 i zobaczmy, co się stanie. Okazuje się, że wyniki nie są takie same! Może to być jednak błąd.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" } }
Uruchomienie tego jako testu JUnit daje następujące wyniki, z różnicą w stosunku do Java wyróżnioną pogrubioną czcionką.
źródło
Dzieje się tak, ponieważ metodę varargs można wywołać z rzeczywistą tablicą, a nie serią elementów tablicy. Kiedy zapewniasz mu niejednoznaczne
null
samo w sobie, zakłada, żenull
jest to plikObject[]
. Przesyłanienull
doObject
rozwiąże ten problem.źródło
wolę
foo(new Object[0]);
aby uniknąć wyjątków wskaźnika Null.
Mam nadzieję, że to pomoże.
źródło
foo()
?Kolejność rozwiązywania problemu przeciążenia metod jest następująca ( https://docs.oracle.com/javase/specs/jls/se11/html/jls-15.html#jls-15.12.2 ):
foo(null)
meczefoo(Object... arg)
zarg = null
w pierwszej fazie.arg[0] = null
byłaby trzecia faza, która nigdy się nie wydarzy.źródło