用单个null参数调用Java可变参数方法?

如果我有一个可变的Java方法foo(Object ...arg)并且我调用foo(null, null) ,那么我将arg[0]arg[1]设为null 。 但是如果我调用foo(null)arg本身就是null。 为什么发生这种情况?

我应该如何调用foo ,使foo.length == 1 && foo[0] == nulltrue

问题是,当你使用字面null时,Java不知道它应该是什么types。 它可能是一个空的对象,或者它可能是一个空的对象数组。 对于一个单一的论点,它假定后者。

你有两个select。 将null显式投射到Object或使用强typesvariables调用该方法。 看下面的例子:

 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)); } } 

输出:

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

你需要一个明确的转换Object

 foo((Object) null); 

否则,参数被认为是可变参数表示的整个数组。

这是因为可变参数方法可以用一个实际的数组而不是一系列的数组元素来调用。 当你自己给它提供模糊的null ,它假定null是一个Object[] 。 将null投射到Object将解决这个问题。

一个testing用例来说明这一点:

具有可变参数方法声明(恰好是静态的)的Java代码:

 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; } } 

这个Java代码(一个JUnit4testing用例)调用上面的代码(我们使用testing用例不是为了testing任何东西,只是为了生成一些输出):

 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"})); } } 

将其作为JUnittesting运行,得出:

 sendNothing():收到的'x'是一个大小为0的数组
 sendNullWithNoCast():收到'x'为空
 sendNullWithCastToString():收到的'x'是一个大小为1的数组
 sendNullWithCastToArray():收到'x'为空
 sendOneValue():收到的'x'是大小为1的数组
 sendThreeValues():收到的'x'是大小为3的数组
 sendArray():收到的'x'是大小为3的数组

为了让这个更有趣,我们从Groovy 2.1.2调用receive()函数,看看会发生什么。 事实certificate,结果是不一样的! 这可能是一个错误。

 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" } } 

以JUnittesting的forms运行这个testing会产生以下结果,不同之处在于以粗体突出显示的Java。

 sendNothing():收到的'x'是一个大小为0的数组
 sendNullWithNoCast():收到'x'为空
 sendNullWithCastToString():收到'x'为空
 sendNullWithCastToArray():收到'x'为空
 sendOneValue():收到的'x'是大小为1的数组
 sendThreeValues():收到的'x'是大小为3的数组
 sendArray():收到的'x'是大小为3的数组

我更喜欢

 foo(new Object[0]); 

避免空指针exception。

希望能帮助到你。