¿Por valor o por referencia?
Me diréis: pero ahora estamos en Java 7, casi la 8.. y ese libro habla de una versión antigua. Cierto, pero la esencia de Java no ha cambiado.
Variables por valor
Entendemos como asignación de variables por valor cuando se hace una copia del valor de una variable a otra. Esto lo vemos así:
public static void main(String[] args) { int a = 10; //es una variable int b = 20; //es otra variable int c = a; //la variable "c" tiene la copia del valor de "a" a = 30; //"a" tiene otro valor System.out.format("a=%d, b=%d, c=%d", a, b, c); //imprime a=30, b=20, c=10 }
Esta asignación también aplica para los parámetros de funciones.
El resultado es:
Valores antes de cambiar a=10, b=20, c=30 Valores cambiados en el método a=100, b=200, c=300 Valores después de cambiar a=10, b=20, c=30
Entonces, estamos claros que, si se asigna otro valor a las variables desde dentro de un método, estos nuevos valores no afectan a las variables originales ¿cierto? Por tanto, estamos casi asegurando de que los parámetros son pasados por valor.
Variables por referencia
¿Qué pasa con los objetos? Revisemos este código:
Listo, terminó mi apunte, y todos estamos satisfechos ¿Verdad que es bonito haber demostrado que los parámetros de tipo nativo son por valor y los de tipo objeto son por referencia?
¿por qué? Porque el código no es el mismo. Lo que hemos cambiado es valor de una variable que pertenece a otra variable.
Me explico.
En el primer ejemplo, se cambió el valor de la variable directamente.. es decir:
private static void cambiandoValores(int a, int b, int c) { a = 100; //se le asigna un nuevo valor... b = 200; //... aquí tambien se le asigna un nuevo valor c = 300; //... idem... notemos que es a la misma variable //....Por tanto, si fuera con objetos... y para ser más justos... deberíamos cambiar directamente a la variable:
//... private static void cambiarNombre(Persona p) { p=new Persona(); //aqui se le está asignado un nuevo valor (objeto) al mismo parámetro recibido p.setNombre("Santiago"); //y...aqui tendrá otro valor } //...Entonces, otra sería la historia. Probemos este último código completo:
El resultado será:
El nombre antes del método es:Diego El nombre en el método es:Santiago El nombre después del método es:Diego
Es lo más justo, es exacto decir:
p=new Persona()
luce igual que a=100
Entonces.. los parámetros son por valor o por referencia?La respuesta es:
Es por valor.. son copias del valor ¿qué guarda la variable de tipo de objeto? Guarda la dirección de la memoria del objeto creado en el heap. No hace diferencia si es tipo nativo o tipo objeto.. siempre es por valor. Kathy Sierra lo describe así en el libro "SCJP Sun Certified Programmer for Java 5 Study Guide"
(Traducción libre:)"No importa si estás pasando una variable primitiva o variables de referencia, siempre estás pasando una copia de los bits de la variable. Así que para una variable primitiva, estás pasando una copia de los bits que representan el valor. Por ejemplo, si se pasa una variable
int
con el valor de 3, está pasando una copia de los bits que representan 3. La llamada al método obtiene su propia copia del valor, para hacer con ella lo que quiera."Y si estás pasando una variable de referencia a objeto, lo que está pasando es una copia de los bits que representan la referencia a un objeto. La llamada al método, entonces, obtiene su propia copia de la variable de referencia, para hacer con ella lo que quiera. Pero debido a que dos variables de referencia idénticas se refieren al mismo objeto, si el método llamado modifica el objeto (mediante la invocación de los métodos setter, por ejemplo), el objeto variable original del llamante ha sido modificado."
Capítulo 3: Asignaciones. Sección "Java usa semánticas por valor?"
Espero que con esto se tenga más claro el uso de las variables en Java.
Con lo expuesto aquí.. la siguiente pregunta es.. ¿Existen punteros en Java?
Que tengan un buen día :)
Actualización (2016-01-08):
Aquí tengo dos ejemplos donde se implementa el mismo ejemplo pero usando los parámetros por valor o por referencia explícitamente. En Pascal se necesita de la instrucciónvar
para que sea por referencia. En C se utiliza con &
y *
Me gusta tu percepción y creo que la comprendo, sin embargo considero que el ejemplo:
ResponderBorrar//...
private static void cambiarNombre(Persona p) {
p=new Persona(); //aqui se le está asignado un nuevo valor (objeto) al mismo parámetro recibido
p.setNombre("Santiago"); //y...aqui tendrá otro valor
}
//...
Cuando se construye la nueva persona se crea para p una nueva referencia y es por eso que el valor de p ahora no cambiara el valor original, ya que el cambio se realizo en una nueva referencia.