使用单个null参数调用Java varargs方法?

pat*_*rit 89 java null language-design variadic-functions

如果我有一个vararg Java方法foo(Object ...arg)并且我打电话foo(null, null),我有两个arg[0]arg[1]作为nulls.但如果我打电话foo(null),arg本身就是空的.为什么会这样?

我怎么称呼foo这样foo.length == 1 && foo[0] == nulltrue

Mik*_*eck 92

问题是当你使用文字null时,Java不知道它应该是什么类型.它可以是null Object,也可以是null Object数组.对于单个参数,它假设后者.

你有两个选择.将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));
   }
}
Run Code Online (Sandbox Code Playgroud)

输出:

foo called, args: [a, b, c]
foo called, args: [null, null]
foo called, args: [null]
foo called, args: [null]
Run Code Online (Sandbox Code Playgroud)

  • @ArunKumar`asList()`是来自`java.util.Arrays`类的静态导入.我只是假设它很明显.虽然现在我正在考虑它,但我可能应该只使用`Arrays.toString()`,因为它转换为List的唯一原因是它会打印漂亮. (5认同)

Boz*_*zho 23

你需要一个明确的演员Object:

foo((Object) null);
Run Code Online (Sandbox Code Playgroud)

否则,该参数被假定为varargs表示的整个数组.


Dav*_*fer 6

一个测试用例来说明这一点:

带有vararg-taking方法声明的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;
    }
}
Run Code Online (Sandbox Code Playgroud)

这个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"}));
    }
}
Run Code Online (Sandbox Code Playgroud)

将此作为JUnit测试运行会产生:

sendNothing(): received 'x' is an array of size 0
sendNullWithNoCast(): received 'x' is null
sendNullWithCastToString(): received 'x' is an array of size 1
sendNullWithCastToArray(): received 'x' is null
sendOneValue(): received 'x' is an array of size 1
sendThreeValues(): received 'x' is an array of size 3
sendArray(): received 'x' is an array of size 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"
    }

}
Run Code Online (Sandbox Code Playgroud)

将此作为JUnit测试运行会生成以下内容,并以粗体突出显示Java的差异.

sendNothing(): received 'x' is an array of size 0
sendNullWithNoCast(): received 'x' is null
sendNullWithCastToString(): received 'x' is null
sendNullWithCastToArray(): received 'x' is null
sendOneValue(): received 'x' is an array of size 1
sendThreeValues(): received 'x' is an array of size 3
sendArray(): received 'x' is an array of size 3