[vc_row][vc_column][vc_column_text]Antes de describir como son pasados los argumentos en Java, es mejor entender como Java almacena las variables en memoria. Básicamente hablamos de dos tipos de variables: primitivas y objetos.
Las variables primitivas siempre son almacenadas en la memoria stack, sin embargo en el caso de los objetos estos son almacenados en dos etapas, los objetos actuales son almacenados en la memoria heap y la referencia a objetos se encuentra almacenada en la memoria stack que apunta a los objetos.[/vc_column_text][/vc_column][/vc_row][vc_row][vc_column][vc_single_image image=»1149″ img_size=»full» alignment=»center»][/vc_column][/vc_row][vc_row][vc_column][vc_column_text]
1. Por valor y Por referencia
Que significa «Por valor» y «Por referencia».
- Por valor: cuando los argumentos son pasados por valor a los métodos, significa que se realiza una copia de la variable y esta es enviada al método y no la original, entonces todo los cambios realizados dentro del método solo afectan a la copia actual.
- Por referencia: cuando los argumentos son pasados por referencia, significa que la referencia o el puntero a la variable original son pasadas a los métodos y no la data original.
2. ¿Como son pasados los argumentos en Java?
En Java, los argumentos son siempre pasados por valor independientemente del tipo de variable. Cada que el método es invocado, pasa lo siguiente:
- Una copia del argumento es pasado en la memoria stack y la copia es pasada en el método
- Si la variable original es primitiva, es simple, una copia de la variable es creada en el stack y esta se pasa al método
- Si la variable original no es primitiva, entonces una nueva referencia o apuntador es creado dentro de la memoria stack que apunta al objeto actual y la nueva referencia es pasada al método, (en esta etapa, 2 referencias apuntan al mismo objeto).
3. Revisando algunas preocupaciones
En el siguiente ejemplo, tratamos de validar «en java siempre se realiza el pase por valor» pasando un conjunto de tipos de argumentos (primitivas, tipos wrappers, colecciones, objetos de negocio) y observar como son modificados despues de la llamada al método.
3.1 Paso de argumentos primitivos:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public static void main(String[] args) { int x = 1; int y = 2; System.out.print("Values of x & y before primitive modification: "); System.out.println(" x = " + x + " ; y = " + y ); modifyPrimitiveTypes(x,y); System.out.print("Values of x & y after primitive modification: "); System.out.println(" x = " + x + " ; y = " + y ); } private static void modifyPrimitiveTypes(int x, int y) { x = 5; y = 10; } |
Salida:
1 2 | Values of x & y before primitive modification: x = 1 ; y = 2 Values of x & y after primitive modification: x = 1 ; y = 2 |
Descripción de la salida:
Las dos variables y y x son tipos primitivos y son almacenadas en la memoria stack. Cuando se llama a modifyPrimitiveTypes(), se realizan dos copias dentro de la memoria stack y luego estas son pasadas al método. Las variables originales no fueron enviadas al método y cualquier modificación dentro del método solo afectan a las copias.[/vc_column_text][/vc_column][/vc_row][vc_row][vc_column][vc_single_image image=»1150″ img_size=»full» alignment=»center»][/vc_column][/vc_row][vc_row][vc_column][vc_column_text]3.2 Paso de argumentos tipo wrappers:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public static void main(String[] args) { Integer obj1 = new Integer(1); Integer obj2 = new Integer(2); System.out.print("Values of obj1 & obj2 before wrapper modification: "); System.out.println("obj1 = " + obj1.intValue() + " ; obj2 = " + obj2.intValue()); modifyWrappers(obj1, obj2); System.out.print("Values of obj1 & obj2 after wrapper modification: "); System.out.println("obj1 = " + obj1.intValue() + " ; obj2 = " + obj2.intValue()); } private static void modifyWrappers(Integer x, Integer y) { x = new Integer(5); y = new Integer(10); } |
Salida:
1 2 | Values of obj1 & obj2 before wrapper modification: obj1 = 1 ; obj2 = 2 Values of obj1 & obj2 after wrapper modification: obj1 = 1 ; obj2 = 2 |
Descripción de la salida:
Los tipos wrappers son almacenados en la memoria heap con la respectiva referencia en la memoria stack.
Cuando se llama a modifyWrappers(), una copia a dicha referencia es creada dentro de la memoria stack y las copias son pasadas a los métodos. Cualquier cambio en la referencia dentro del método modifica el valor de las referencias y no los valores originales.[/vc_column_text][/vc_column][/vc_row][vc_row][vc_column][vc_single_image image=»1146″ img_size=»full» alignment=»center»][/vc_column][/vc_row][vc_row][vc_column][vc_column_text]Nota:
Si realiza un cambio de una variable del tipo wrapper dentro del método de la siguiente forma: x+=2, el cambio no se refleja fuera del método desde que los objetos wrapper son inmutables, lo que significa que se crea una nueva instancia cada que el estado es modificado. Los objetos String funcionan en forma similar a los objetos wrappers, aplican las mismas reglas.[/vc_column_text][/vc_column][/vc_row][vc_row][vc_column][vc_column_text]3.3 Paso de colecciones como argumentos:
1 2 3 4 5 6 7 8 9 10 11 12 | public static void main(String[] args) { List lstNums = new ArrayList(); lstNums.add(1); System.out.println("Size of list before List modification = " + lstNums.size()); modifyList(lstNums); System.out.println("Size of list after List modification = " + lstNums.size()); } private static void modifyList(List lstParam) { lstParam.add(2); } |
Salida:
1 2 | Size of list before List modification = 1 Size of list after List modification = 2 |
Descripción de la salida:
Cuando se define un ArrayList o cualquier colección en Java, la referencia es creada dentro del stack y esta apunta a múltiples objetos que son almacenados en la memoria heap. Cuando se llama a modifyList(), una copia de la referencia es creada y se pasa al método, entonces el objeto actual tiene 2 referencias y cualquier cambio realizado a una referencia se refleja en la otra.
Dentro del método, llamamos a lstParam(2), que actualmente trata de crear un nuevo objeto Integer en la memoria heap y se enlaza a la lista actual de objetos. Por lo tanto la lista original puede ver las modificaciones desde que ambas referencias apuntan al mismo objeto en memoria.
[/vc_column_text][/vc_column][/vc_row][vc_row][vc_column][vc_single_image image=»1147″ img_size=»full» alignment=»center»][/vc_column][/vc_row][vc_row][vc_column][vc_column_text]3.4 Paso de objetos de negocios como argumentos
1 2 3 4 5 6 7 8 9 10 11 12 | public static void main(String[] args) { Student student = new Student(); System.out.println("Value of name before Student modification = " + student.getName()); modifyStudent(student); System.out.println("Value of name after Student modification = " + student.getName()); } private static void modifyStudent(Student student) { student.setName("Alex"); } |
Salida:
1 2 | Value of name before Student modification = null Value of name after Student modification = Alex |
Descripción de la salida:
El objeto student es creado dentro de la memoria heap y la referencia se encuentra en la memoria stack, cuando se llama a modifyStudent(), una copia de la referencia es creado dentro del stack y esta se pasa al método. Cualquier modificación dentro de los atributos del objetos dentro del método son reflejadas en la referencia original.[/vc_column_text][/vc_column][/vc_row][vc_row][vc_column][vc_single_image image=»1148″ img_size=»full» alignment=»center»][/vc_column][/vc_row][vc_row][vc_column][vc_column_text]
4. Conclusión
En Java, los argumentos son pasados por valor, la copia puede ser una referencia o una variable dependiendo del tipo original de la variable. Desde ahora, usted puede utilizar las siguientes recomendaciones a fin de entender como la modificación de argumentos dentro del método afectan a la variable original:
- La modificación de valores tipos primitivos, nunca afectan a la variable original
- Si se cambia la referencia al objeto dentro del método esto nunca afecta a la referencia original, sin embargo esto crea un nuevo objeto en la memoria heap.
- Modificar los atributos de un objeto pasado como argumento se refleja fuera del método.
- Modificar colecciones y maps siempre se reflejan fuera del método.
Este artículo se encuentra basado en Java – pass by reference or pass by value. Consideramos que es un concepto importante y que en realidad muy pocos conocen, pues por lo general no es tocado dentro de los cursos de programación.
Si les parece interesante o tienen un aporte adicional, por favor, dejen sus comentarios.[/vc_column_text][/vc_column][/vc_row]
estaba buscando esta info, gracias por la explicación