如果我有一个可变参数 Java 方法 foo(Object ...arg)
,并且我调用 foo(null, null)
,那么我会得到 arg[0]
和 arg[1]
都是 null
。但是如果我调用 foo(null)
,arg
本身就是 null
。为什么会这样发生?
我应该如何调用 foo
使得 foo.length == 1 && foo[0] == null
返回 true
?
如果我有一个可变参数 Java 方法 foo(Object ...arg)
,并且我调用 foo(null, null)
,那么我会得到 arg[0]
和 arg[1]
都是 null
。但是如果我调用 foo(null)
,arg
本身就是 null
。为什么会这样发生?
我应该如何调用 foo
使得 foo.length == 1 && foo[0] == null
返回 true
?
问题在于,当您使用字面量null时,Java不知道它应该是什么类型。它可以是一个null对象,也可以是一个null对象数组。对于单个参数,它假定是后者。
您有两个选择。将null显式转换为Object或使用强类型变量调用方法。请参见下面的示例:
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);
否则,假定该参数是varargs所表示的整个数组。一个用来说明的测试案例:
带有可变参数方法声明的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;
}
}
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"}));
}
}
sendNothing(): 接收到的 'x' 是大小为0的数组 sendNullWithNoCast(): 接收到的 'x' 为空 sendNullWithCastToString(): 接收到的 'x' 是大小为1的数组 sendNullWithCastToArray(): 接收到的 'x' 为空 sendOneValue(): 接收到的 'x' 是大小为1的数组 sendThreeValues(): 接收到的 'x' 是大小为3的数组 sendArray(): 接收到的 'x' 是大小为3的数组为了使这更有趣,让我们从Groovy 2.1.2中调用
receive()
函数并看看会发生什么。结果表明,结果并不相同!虽然这可能是一个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"
}
}
将其作为JUnit测试运行,将产生以下结果,Java与之间的差异以粗体突出显示。
sendNothing():接收到的“x”是大小为0的数组 sendNullWithNoCast():接收到的“x”为空 sendNullWithCastToString():接收到的“x”为空 sendNullWithCastToArray():接收到的“x”为空 sendOneValue():接收到的“x”是大小为1的数组 sendThreeValues():接收到的“x”是大小为3的数组 sendArray():接收到的“x”是大小为3的数组
null
时,它会假定null
是一个Object[]
。将null
强制转换为Object
即可解决此问题。foo(null)
与 foo(Object... arg)
在第一阶段匹配,其中arg = null
。 arg[0] = null
应该是第三阶段,但这一步骤从未发生。
foo(new Object[0]);
避免空指针异常。
希望能够帮到您。
foo()
这样调用它呢? - BrainStorm.exe
asList
方法及其用途,将对其他人有所帮助。 - Arun KumarasList()
是java.util.Arrays
类的静态导入。我只是认为这是显而易见的。虽然现在我在考虑,我可能应该使用Arrays.toString()
,因为它被转换为列表的唯一原因是为了打印漂亮。 - Mike Deck