Подтвердить что ты не робот

Почему varargs должен быть последним в сигнатуре метода?

Если я попытаюсь написать метод, подобный ниже

public void someStuff(Object ... args, String a )

Я получаю эту ошибку

Тип аргумента переменной Объект метода someStuff должен быть последним параметром.

Я не совсем понимаю требование переменной типа аргумента быть последним. Любые входы будут полезны.

4b9b3361

Ответ 1

Это следует за соглашением C. Соглашение C в свою очередь основано на архитектурах CPU, которые передают аргументы в стеке. Первые аргументы без vararg заканчиваются с фиксированным смещением в стеке. Если вы могли бы сначала перенести аргументы vararg, смещение стека из следующих аргументов будет зависеть от того, сколько параметров vararg вы бы прошли. Это значительно усложнит количество кода, необходимого для доступа к ним.

В вашем примере с String a сначала, концептуально при смещении 0, независимо от количества последующих аргументов vararg. Но с String a последним он может быть со смещением 0, 4, 8, 12 и т.д. - вам приходилось вычислять args.size * 4 каждый раз, когда вам нужно String a.

Ответ 2

Аргумент переменной должен быть последним, поэтому компилятор может определить, какой аргумент является.

Например, скажите, что вы проходите

"test", "test", "test", "test"

в вашу функцию

public void someStuff(Object ... args, String a)

Java не может работать, если вы хотите, чтобы переменная args содержала 3 или 4 строки. Это может быть очевидно вам на момент написания, но это двусмысленно.

Однако, когда это наоборот

public void someStuff(String a, Object ... args)

Компилятор Java видит первую строку, вставляет ее в "a", а затем знает, что оставшиеся строки можно безопасно помещать в args, и нет никакой двусмысленности в отношении переменных.

Ответ 3

Потому что это сделает язык излишне сложным. Представьте, что вы также разрешили другие синтаксисы:

public void someStuff(String a, Object ... args, String b)
{
}

Или даже:

public void someStuff(String a, Object ... args, int b, Object ... args2)
{
}

Этот второй синтаксис означает строку, за которой следует любое количество аргументов типа Object, за которым следует целое число, за которым следует больше объектов. Конечно, вы могли бы разработать язык, который мог бы принимать такие вещи, но что, если вы также хотели указать, что args2 должен содержать хотя бы один элемент, но аргументы могут быть пустыми? Почему мы тоже не можем это сделать? Вы можете создать такой язык.

Это сводится к тому, насколько сложно вы должны соблюдать правила? В этом случае они выбрали простой вариант, который удовлетворяет потребности.

Ответ 4

Ну, String также является экземпляром Object, поэтому, если вы используете varargs, ваш массив vararg должен быть последним параметром, потому что компилятор не может решить, что такое args, и что такое ваша строка a. Подумайте о вызове метода как кортежа имени метода и списка объектов, которые являются вашими параметрами. Если у вас есть два метода:

public void someStuff(Object ... args, String a )
public void someStuff(String a, String b)

Компилятор не мог решить, какой метод выбрать для someStuff ( "Hello", "Hello" ). Если вы поместите свой String a в качестве первого аргумента, он может решить, что someStuff (String, String) более специфичен, чем someStuff (String, Object).

Ответ 5

Учитывая, как используется метод с var args, любой другой формат может привести к двусмысленности. Наличие последних varargs предотвращает возможные двусмысленности, не требуя дополнительного синтаксиса для устранения двусмысленностей, что уменьшит преимущество этой функции.

Рассмотрим декларацию следующего метода:

public void varargsAreCool(String surname, String firstname, 
                           String... nicknames) {
    // some cool varargs logic
}

При использовании, как varargsAreCool("John", "Smith"), очевидно, что John Smith не имеет псевдонимов. При использовании этого типа varargsAreCool("Andrew", "Jones", "The Drew", "Jonesy").

Теперь рассмотрим следующее недопустимое объявление метода:

public void varargsAreCool(String surname, String... nicknames,
                           String firstname) {
    // some cool varargs logic
}

При использовании как varargsAreCool("John", "Smith") есть Smith John nickname или его фамилия? Если это его фамилия, как я могу указать, что у него нет прозвищ? Для этого вам, вероятно, придется использовать метод, подобный этому varargsAreCool("John", new String[]{}, "Smith"), который неудобен и несколько поражает цель этой функции.

При использовании этого типа varargsAreCool("Andrew", "The Drew", "Jonesy", "Jones") есть The Drew, Jonesy and Jones все псевдонимы и фамилия отсутствует? Снова эта неоднозначность может быть решена, но ценой неуклюжего дополнительного синтаксиса.

Ответ 6

Это пятое правило Var-args GeekOnJava:

Чтобы подготовить объект массива, как показано в приведенной выше программе, если мы хотим объявить var-args, поскольку первый или второй компилятор параметров не будет иметь подскажите, сколько аргументов должно быть включено в объект массива.

И согласно пятому правилу:

Мы не можем объявлять несколько параметров var-arg, даже если они разные. Потому что, компилятор не знает, сколько значений сначала нужно создать объект массива var-arg. Это приводит к ошибке времени компиляции.

public void add(int... a,int...b){}//leads compile time error
public void add(int... a,long...b){} //compile time error

в приведенном выше сценарии компилятор говорит -

Тип аргумента переменной int для добавления метода должен быть последним Параметр