Answers:
问题是,当您使用原义null时,Java不知道它应该是哪种类型。它可以是空对象,也可以是空对象数组。对于单个参数,假定为后者。
您有两种选择。将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]
asList()
是该类的静态导入java.util.Arrays
。我只是认为这很明显。尽管现在我正在考虑它,但我大概应该使用它,Arrays.toString()
因为将它转换为List的唯一原因是它可以打印得漂亮。
您需要显式转换为Object
:
foo((Object) null);
否则,假定参数为varargs表示的整个数组。
一个测试用例来说明这一点:
带有vararg-take方法声明的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代码(一个JUnit4测试用例)调用了上面的代码(我们使用该测试用例不测试任何东西,只是生成一些输出):
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"}));
}
}
将其作为JUnit测试运行将产生:
sendNothing():收到的“ x”是大小为0的数组 sendNullWithNoCast():收到的“ x”为空 sendNullWithCastToString():收到的“ x”是大小为1的数组 sendNullWithCastToArray():收到的“ x”为空 sendOneValue():接收到的“ x”是大小为1的数组 sendThreeValues():收到的“ x”是大小为3的数组 sendArray():收到的“ x”是大小为3的数组
为了使这个更有趣,让我们receive()
从Groovy 2.1.2 调用该函数,然后看看会发生什么。原来结果不一样!虽然这可能是一个错误。
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的数组
我更喜欢
foo(new Object[0]);
避免Null指针异常。
希望能帮助到你。
foo()
呢?
方法重载解析的顺序为(https://docs.oracle.com/javase/specs/jls/se11/html/jls-15.html#jls-15.12.2):
第一阶段执行重载解析,不允许装箱或拆箱转换,也不允许使用可变arity方法调用。如果在此阶段未找到适用的方法,则处理将继续进行到第二阶段。
这样可以保证,由于引入了可变arity方法,隐式装箱和/或拆箱,在Java SE 5.0之前在Java编程语言中有效的任何调用都不会被认为是模棱两可的。但是,声明可变可变方法(第8.4.1节)可以更改为给定方法方法调用表达式选择的方法,因为可变可变方法在第一阶段被视为固定可变方法。例如,在已经声明了m(Object)的类中声明m(Object ...)会导致不再为某些调用表达式(例如m(null))选择m(Object),例如m(Object [] )更具体。
第二阶段执行重载解析,同时允许装箱和拆箱,但仍排除使用可变arity方法调用。如果在此阶段未找到适用的方法,则处理将继续进行到第三阶段。
这样可以确保如果通过固定arity方法调用适用方法,则永远不会通过可变arity方法调用选择方法。
第三阶段允许将重载与可变arity方法,装箱和拆箱相结合。
foo(null)
匹配foo(Object... arg)
与arg = null
在第一阶段。 arg[0] = null
将是第三阶段,这永远不会发生。
asList
在样本中列出了方法及其目的,将对其他人有所帮助。