Вызов метода Java varargs с одним нулевым аргументом?


если у меня есть метод с переменным числом аргументов в Java foo(Object ...arg) и я называю foo(null, null), У меня есть оба arg[0] и arg[1] как nulls. но если я позвоню foo(null),arg сам по себе равен нулю. Почему это происходит?

как позвонить foo такое, что foo.length == 1 && foo[0] == null и true?

5 80

5 ответов:

проблема в том, что при использовании литерала null Java не знает, какой тип он должен быть. Это может быть нулевой объект или массив нулевых объектов. Для одного аргумента он предполагает последнее.

у вас есть два варианта. Приведите значение null явно к объекту или вызовите метод с помощью строго типизированной переменной. Смотрите пример ниже:

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 с объявлением метода vararg-taking (который оказывается статическим):

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(): 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

чтобы сделать это более интересным, назовем

это связано с тем, что метод varargs может быть вызван с фактическим массивом, а не с серией элементов массива. Когда вы предоставляете его с неоднозначным null сам по себе он предполагает null Это Object[]. Кастинг null до Object исправит это.

предпочитаю

foo(new Object[0]);

чтобы избежать исключение указателя null.

надеюсь, что это помогает.