Відповіді:
Проблема в тому, що коли ви використовуєте літерал null, Java не знає, якого типу він повинен бути. Це може бути нульовий об’єкт, або це може бути нульовий масив об’єкта. Для одного аргументу він передбачає останній.
У вас є два варіанти. Віддайте нуль явно 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()
оскільки єдина причина, через яку він перетворюється на Список, полягає в тому, що він буде друкуватися досить.
Вам потрібен явний привід для Object
:
foo((Object) null);
В іншому випадку аргументом вважається весь масив, який представляють varargs.
Тестовий випадок для ілюстрації:
Код Java із декларацією методу, що приймає vararg (яка буває статичною):
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' має значення null 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' має значення null sendNullWithCastToArray (): отриманий 'x' має значення null sendOneValue (): отриманий 'x' - це масив розміром 1 sendThreeValues (): отриманий 'x' - це масив розміром 3 sendArray (): отриманий 'x' - це масив розміром 3
я віддаю перевагу
foo(new Object[0]);
щоб уникнути винятків з нульовим покажчиком.
Сподіваюся, це допомагає.
foo()
?
Впорядкування дозволу на перевантаження методу є ( https://docs.oracle.com/javase/specs/jls/se11/html/jls-15.html#jls-15.12.2 ):
Перша фаза виконує дозвіл на перевантаження, не дозволяючи перетворення боксу чи розпакування, або використання методу змінної arity. Якщо на цій фазі не знайдено жодного застосовного методу, то обробка продовжується до другої фази.
Це гарантує, що будь-які дзвінки, які були дійсними в мові програмування Java до Java SE 5.0, не вважатимуться двозначними в результаті впровадження методів змінної arity, неявного боксу та / або розпакування. Однак оголошення методу змінної сутності (§8.4.1) може змінити метод, обраний для виразу виклику методу даного методу, оскільки метод змінної сутності на першій фазі розглядається як метод фіксованої сутності. Наприклад, оголошення m (Object ...) у класі, який вже оголошує m (Object), призводить до того, що m (Object) більше не вибирається для деяких виразів виклику (наприклад, m (null)), як m (Object [] ) є більш конкретним.
Друга фаза виконує роздільну здатність перевантаження, дозволяючи бокс і розпаковування, але все ще виключає використання методу змінної arity. Якщо на цій фазі не знайдено жодного застосовного методу, то обробка продовжується до третьої фази.
Це гарантує, що метод ніколи не вибирається за допомогою виклику методу змінної arity, якщо він застосовується за допомогою виклику методу фіксованої arity.
Третя фаза дозволяє поєднувати перевантаження з методами змінної артерії, боксу та розпакування.
foo(null)
матчі foo(Object... arg)
з arg = null
на першій фазі. arg[0] = null
буде третьою фазою, яка ніколи не відбувається.
asList
метод у зразку та його мету.