2011-03-23 8 views
27

Varargs:Java varags lista de métodos parámetro frente a matriz

public static void foo(String... string_array) { ... } 

frente

gama Individual param:

public static void bar(String[] string_array) { ... } 

Java 1.6 parece aceptar/rechazar la siguiente:

String[] arr = {"abc", "def", "ghi"}; 
foo(arr); // accept 
bar(arr); // accept 
foo("abc", "def", "ghi"); // accept 
bar("abc", "def", "ghi"); // reject 

Suponiendo que lo anterior es true/correct, ¿por qué no siempre usar varargs en lugar de solo param array? Parece agregar un toque de flexibilidad de llamadas de forma gratuita.

¿Puede un experto compartir la diferencia de JVM interna, si hay una?

Gracias.

Respuesta

31

matrices han existido desde el principio de Java, mientras que varargs son una adición bastante reciente. Por lo tanto, una gran cantidad de código más viejo todavía felizmente utiliza matrices.

Nótese también que llamar a un método vararg genérico con un parámetro de matriz explícita puede silencio causa un comportamiento diferente al esperado:

public <T> void foo(T... params) { ... } 

int[] arr = {1, 2, 3}; 

foo(arr); // passes an int[][] array containing a single int[] element 

Por lo tanto - aparte de requerir un gran esfuerzo para obtener ningún beneficio claro - no es siempre deseable para reemplazar los parámetros de matriz heredados con varargs.

no hablar de los casos en los que no se puede, porque hay otro parámetro después de la matriz en la lista de parámetros método:

public void foo(String[] strings, String anotherParam) { ... } 

Reordenación de los parámetros puede resolver técnicamente esto, sin embargo, se rompe el código del cliente.

Actualización: Effective Java 2nd. Edición, artículo 42: Utilice varargs juiciosamente explica esto con más detalle, dando también un ejemplo concreto: Arrays.asList() se adaptó en Java5 para tener parámetros vararg, que inadvertidamente rompió una gran cantidad de código existente puede causar sorpresas al usar esto (ahora obsoleta) modismo para imprimir una matriz:

System.out.println(Arrays.asList(myArray)); 

Update2: doble comprobación de la fuente, y se dice que el problema occurrs con arreglos de tipos primitivos, como int[].Antes varargs, código como este:

int[] digits = { 3, 1, 4, 1, 5, 9, 2, 6, 5, 4 }; 
System.out.println(Arrays.asList(digits)); 

emitiría un error de compilación, porque sólo los arreglos de tipos de referencia podrían ser convertidos a un List. Desde varargs, y la modificación de asList, el código anterior se compila sin advertencias, y el resultado involuntario es algo así como "[[[email protected]]".

+0

"pasa una matriz String [] [] que contiene un único elemento String []" no puede reproducir este – user102008

+0

Para aclarar, puede incluir otro parámetro en la firma que no tome varargs, pero [el vararg- el parámetro de aceptación debe ir al último] (http://docs.oracle.com/javase/1.5.0/docs/guide/language/varargs.html). Además, en el ejemplo anterior, al llamar 'foo (arr);' hace que el compilador genere un 'String []' que contiene el 'String []' que pasaste. En otras palabras, genera un 'String' bidimensional array, que es un 'String [] []'. – hotshot309

+2

** Totalmente incorrecto **. Pasar una matriz no primitiva a un parámetro varargs NO dará como resultado una matriz bidimensional. Explicado [aquí] (http://stackoverflow.com/a/2926653/159570) y probado fácilmente. –

2

en foo especifica tres params, que tendría que llamar barra de la siguiente manera:

bar(new String[]{"abc", "def", "ghi"}); 

para que sólo lo llama con un parámetro, que es la cadena [] en este caso, esto tiene casi nada que ver con internos, la firma de su método para la barra de métodos simplemente indica que solo tiene un parámetro, mientras que foo tiene n parámetros que son todas las cadenas

2

Esto es así, cómo se definen las variables. La extensión varargs no hace que cada función de aceptación de matriz sea una función varargs. Tienes que llamar a la barra como esta:

bar(new String[]{"abc", "def", "ghi"}) 
4

Un vararg es azúcar sintáctico simple para una matriz.

si se llama a continuación foo("abc", "def", "ghi"); compilador llamará como foo(new String[] {"abc", "def", "ghi"});

compilador creará una nueva matriz y pasarlo a foo(). Uno no puede tener foo(String...) y foo(String[]). Dado que ambos son funcionalmente iguales.

7

La razón principal para no especificar todo como varargs es que no siempre tiene sentido. Por ejemplo, si InputStream.read(byte[]) donde define como `leer (byte ...) la siguiente llamada sería válida:

myInputStream.read(0, 1, 2, 3); 

Esto crearía una matriz de bytes de 4 elementos, pasarlo y luego descartarlo.

1

Otra diferencia es la eficiencia. Los objetos que están dentro de una matriz explícita no serán invocados. Sin embargo, los parámetros de una lista de argumentos variables se evalúan cuando se empuja el método en la pila.

Esto es evidente cuando una llamada de función se pasa como un parámetro que devuelve el tipo que se utiliza en la lista de argumentos de variables.

Ejemplo: someMethod (Object ... x) anotherMethod (Object []);

someMethod (a(), b(), c()); // a, byc se invocarán antes de ingresar al método.

anotherMethod (new Object [] {a(), b(), c()}); // Los métodos no se invocan hasta que se accede a los objetos.

+0

'Los métodos no se invocan hasta que se accede a los objetos': Sorprendente! ¿Significa esto que si no accedo a los objetos en un método, nunca se llaman? Además, ¿compiló y ejecutó este código para confirmar el comportamiento? – kevinarpe

+1

La razón por la que no se invocan los parámetros del objeto en el ejemplo que di es porque están incrustados en la matriz del objeto []. Se invocarán cuando los miembros de la matriz se procesen, pero no en el momento de ser enviados a la pila para la invocación del método original. –

Cuestiones relacionadas