varargs vararg parametros indefinidos argumentos java method-signature

java - parametros - vararg kotlin



¿Por qué varargs debería ser el último en la firma del método? (6)

Si intento escribir un método como el siguiente

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

Me sale este error

El tipo de argumento variable Objeto del método someStuff debe ser el último parámetro.

No entiendo completamente el requisito de que el tipo de argumento variable sea el último. Cualquier entrada será útil.


Bueno, una cadena es también una instancia de Object, por lo tanto, si está utilizando varargs, su matriz vararg debe ser el último parámetro porque el compilador no puede realmente decidir qué es args y cuál es su cadena a. Piense en la llamada al método como una tupla de nombre de método y una lista de objetos que son sus parámetros. Si tienes dos métodos como este:

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

El compilador no pudo decidir qué método elegir para algunas cosas ("Hola", "Hola"). Si coloca su String a como primer argumento, puede decidir que someStuff (String, String) es más específico que someStuff (String, Object).


Dado que un método con var args se usa, cualquier otro formato podría llevar a ambigüedades. Tener el último varargs evita posibles ambigüedades sin requerir una sintaxis adicional para resolver las ambigüedades que reducirían el beneficio de la función.

Considere la siguiente declaración de método:

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

Cuando se usa como varargsAreCool("John", "Smith") es obvio que John Smith no tiene apodos. Cuando se usa como este varargsAreCool("Andrew", "Jones", "The Drew", "Jonesy") .

Ahora considere la siguiente declaración de método inválido:

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

Cuando se usa como varargsAreCool("John", "Smith") es el apodo de Smith John o su apellido? Si es su apellido, ¿cómo indico que no tiene apodos? Para hacer esto, es probable que tengas que usar el método como este varargsAreCool("John", new String[]{}, "Smith") que es torpe y de alguna manera anula el propósito de la función.

Cuando se usan de esta manera, varargsAreCool("Andrew", "The Drew", "Jonesy", "Jones") son los apodos de The Drew, Jonesy and Jones y ¿falta el apellido? Nuevamente, esta ambigüedad podría resolverse, pero a costa de una sintaxis adicional compleja.


El argumento variable tiene que ser el último para que el compilador pueda determinar qué argumento es cuál.

Por ejemplo, digamos que pasa

"prueba", "prueba", "prueba", "prueba"

en tu función

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

Java no puede funcionar si desea que la variable args contenga 3 o 4 cadenas. Puede ser obvio para usted al momento de escribir, pero es ambiguo.

Sin embargo, cuando es al revés

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

El compilador de Java ve la primera cadena, la pega en "a" y luego sabe que las cadenas restantes se pueden colocar de forma segura en args y no hay ambigüedad sobre las variables.


Es la quinta regla de Var-args por el artículo de GeekOnJava :

Para preparar el objeto de matriz como se muestra en el programa anterior, si queremos declarar var-args como primer o segundo parámetro, el compilador no tendrá idea de cuántos argumentos deben incluirse en el objeto de matriz.

Y según la quinta regla:

No podemos declarar múltiples parámetros var-arg aunque sean tipos diferentes. Porque, el compilador no tiene idea de cuántos valores debe crearse primero el objeto de matriz var-arg. Lleva a compilar el error de tiempo.

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

en el escenario anterior el compilador dice:

El tipo de argumento variable int del método add debe ser el último parámetro


Porque eso haría el lenguaje innecesariamente complejo. Imagínate si también permitieras otras sintaxis:

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

O incluso:

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

Esta segunda sintaxis significa una cadena seguida por cualquier número de argumentos de tipo Objeto, seguidos por un número entero, seguido por más objetos. Claro que puedes diseñar un lenguaje que pueda aceptar cosas así, pero ¿qué pasa si también quieres especificar que args2 debe contener al menos un elemento, pero args puede estar vacío? ¿Por qué no podemos hacer eso también? Podrías diseñar tal lenguaje.

Se reduce a, ¿qué tan complicado quieres que sean las reglas? En este caso eligieron una opción simple que satisface las necesidades.


Sigue la convención de C. La convención de C a su vez se basa en arquitecturas de CPU que pasan argumentos en la pila. Los primeros argumentos que no son vararg terminan en un desplazamiento fijo en el cuadro de pila. Si pudiera poner primero los argumentos vararg, el desplazamiento de la pila de los siguientes argumentos dependería de cuántos parámetros vararg habría pasado. Esto complicaría enormemente la cantidad de código necesario para acceder a ellos.

En su ejemplo, con String a first, conceptualmente en offset 0 es independiente de la cantidad de argumentos vararg que siguen. Pero con String a last, podría estar en el offset 0, 4, 8, 12, etc., tendría que calcular args.size * 4 cada vez que necesitaba String a .