¿Java pasa por referencia o pasa por valor?

Muchos lenguajes de programación permiten pasar parámetros por referencia o por valor . En Java, solo podemos pasar parámetros por valor . Esto impone algunos límites y también plantea interrogantes. Por ejemplo, si el valor del parámetro se cambia en el método, ¿qué sucede con el valor después de la ejecución del método? También puede preguntarse cómo administra Java los valores de los objetos en el montón de memoria. Este Java Challenger lo ayuda a resolver estas y otras preguntas comunes sobre referencias a objetos en Java.

Obtén el código fuente

Obtenga el código para este Java Challenger. Puede ejecutar sus propias pruebas mientras sigue los ejemplos.

Las referencias a objetos se pasan por valor

Todas las referencias a objetos en Java se pasan por valor. Esto significa que se pasará una copia del valor a un método. Pero el truco es que pasar una copia del valor también cambia el valor real del objeto. Para entender por qué, comience con este ejemplo:

 public class ObjectReferenceExample { public static void main(String... doYourBest) { Simpson simpson = new Simpson(); transformIntoHomer(simpson); System.out.println(simpson.name); } static void transformIntoHomer(Simpson simpson) { simpson.name = "Homer"; } } class Simpson { String name; } 

¿Qué crees que simpson.nameserá después de transformIntoHomerque se ejecute el método?

En este caso, ¡será Homer! La razón es que las variables de objeto Java son simplemente referencias que apuntan a objetos reales en el montón de memoria. Por lo tanto, aunque Java pasa parámetros a métodos por valor, si la variable apunta a una referencia de objeto, el objeto real también cambiará.

Si aún no tiene muy claro cómo funciona esto, eche un vistazo a la siguiente figura.

Rafael Chinelato Del Nero

¿Se pasan los tipos primitivos por valor?

Al igual que los tipos de objeto, los tipos primitivos también se pasan por valor. ¿Puedes deducir qué pasará con los tipos primitivos en el siguiente ejemplo de código?

 public class PrimitiveByValueExample { public static void main(String... primitiveByValue) { int homerAge = 30; changeHomerAge(homerAge); System.out.println(homerAge); } static void changeHomerAge(int homerAge) { homerAge = 35; } } 

Si determinó que el valor cambiaría a 30, está en lo correcto. Es 30 porque (nuevamente) Java pasa parámetros de objeto por valor. El número 30 es solo una copia del valor, no el valor real. Los tipos primitivos se asignan en la memoria de la pila, por lo que solo se cambiará el valor local. En este caso, no hay referencia de objeto.

Pasando referencias de objetos inmutables

¿Y si hiciéramos la misma prueba con un Stringobjeto inmutable ?

El JDK contiene muchas clases inmutables. Los ejemplos incluyen los tipos de envoltura Integer, Double, Float, Long, Boolean, BigDecimal, y por supuesto la muy conocida Stringclase.

En el siguiente ejemplo, observe lo que sucede cuando cambiamos el valor de a String.

 public class StringValueChange { public static void main(String... doYourBest) { String name = ""; changeToHomer(name); System.out.println(name); } static void changeToHomer(String name) { name = "Homer"; } } 

¿Cuál crees que será la salida? Si adivinaste “”, ¡felicitaciones! Eso sucede porque un Stringobjeto es inmutable, lo que significa que los campos dentro del Stringson finales y no se pueden cambiar.

Hacer que la Stringclase sea inmutable nos da un mejor control sobre uno de los objetos más usados ​​de Java. Si se Stringpudiera cambiar el valor de a , se crearían muchos errores. También tenga en cuenta que no estamos cambiando un atributo de la Stringclase; en cambio, simplemente le estamos asignando un nuevo Stringvalor. En este caso, el valor “Homer” se pasará a nameen el changeToHomermétodo. El String"Homer" será elegible para ser recolectado como basura tan pronto como el changeToHomermétodo complete la ejecución. Aunque el objeto no se puede cambiar, la variable local lo será.

Cuerdas y más

Obtenga más información sobre la Stringclase de Java y más: vea todas las publicaciones de Rafael en la serie Java Challengers.

Pasando referencias a objetos mutables

A diferencia String, la mayoría de los objetos del JDK son mutables, como la StringBuilderclase. El siguiente ejemplo es similar al anterior, pero presenta en StringBuilderlugar de String:

 static class MutableObjectReference { public static void main(String... mutableObjectExample) { StringBuilder name = new StringBuilder("Homer "); addSureName(name); System.out.println(name); } static void addSureName(StringBuilder name) { name.append("Simpson"); } } 

¿Puede deducir el resultado de este ejemplo? En este caso, debido a que estamos trabajando con un objeto mutable, la salida será "Homer Simpson". Podría esperar el mismo comportamiento de cualquier otro objeto mutable en Java.

Ya aprendió que las variables de Java se pasan por valor, lo que significa que se pasa una copia del valor. Solo recuerde que el valor copiado apunta a un objeto real en el montón de memoria Java. Pasar por valor aún cambia el valor del objeto real.

¡Acepta el desafío de referencias a objetos!

En este Java Challenger probaremos lo que ha aprendido sobre referencias de objetos. En el siguiente ejemplo de código, verá la clase inmutable Stringy mutable StringBuilder. Cada uno se pasa como parámetro a un método. Sabiendo que Java solo pasa por valor, ¿cuál cree que será el resultado una vez que se ejecute el método principal de esta clase?

 public class DragonWarriorReferenceChallenger { public static void main(String... doYourBest) { StringBuilder warriorProfession = new StringBuilder("Dragon "); String warriorWeapon = "Sword "; changeWarriorClass(warriorProfession, warriorWeapon); System.out.println("Warrior=" + warriorProfession + " Weapon=" + warriorWeapon); } static void changeWarriorClass(StringBuilder warriorProfession, String weapon) { warriorProfession.append("Knight"); weapon = "Dragon " + weapon; weapon = null; warriorProfession = null; } } 

Estas son las opciones, consulte el final de este artículo para obtener la clave de respuestas.

A : Guerrero = nulo Arma = nulo

B : Guerrero = Dragón Arma = Dragón

C : Guerrero = Caballero Dragón Arma = Espada Dragón

D : Guerrero = Caballero Dragón Arma = Espada

¿Qué acaba de pasar?

El primer parámetro del ejemplo anterior es la warriorProfessionvariable, que es un objeto mutable. El segundo parámetro, arma, es inmutable String:

 static void changeWarriorClass(StringBuilder warriorProfession, String weapon) { ... } 

Now let’s analyze what is happening inside this method. At the first line of this method, we append the Knight value to the warriorProfession variable. Remember that warriorProfession is a mutable object; therefore the real object will be changed, and the value from it will be “Dragon Knight.”

 warriorProfession.append("Knight"); 

In the second instruction, the immutable local String variable will be changed to “Dragon Sword.” The real object will never be changed, however, since String is immutable and its attributes are final:

 weapon = "Dragon " + weapon; 

Finally, we pass null to the variables here, but not to the objects. The objects will remain the same as long as they are still accessible externally--in this case through the main method. And, although the local variables will be null, nothing will happen to the objects:

 weapon = null; warriorProfession = null; 

From all of this we can conclude that the final values from our mutable StringBuilder and immutable String will be:

 System.out.println("Warrior=" + warriorProfession + " Weapon=" + warriorWeapon); 

The only value that changed in the changeWarriorClass method was warriorProfession, because it’s a mutable StringBuilder object. Note that warriorWeapon did not change because it’s an immutable String object.

The correct output from our Challenger code would be:

D: Warrior=Dragon Knight Weapon=Sword.

Video challenge! Debugging object references in Java

Debugging is one of the easiest ways to fully absorb programming concepts while also improving your code. In this video you can follow along while I debug and explain object references in Java.

Common mistakes with object references

  • Trying to change an immutable value by reference.
  • Trying to change a primitive variable by reference.
  • Expecting the real object won't change when you change a mutable object parameter in a method.

What to remember about object references

  • Java always passes parameter variables by value.
  • Object variables in Java always point to the real object in the memory heap.
  • A mutable object’s value can be changed when it is passed to a method.
  • An immutable object’s value cannot be changed, even if it is passed a new value.
  • “Passing by value” refers to passing a copy of the value.
  • “Passing by reference” refers to passing the real reference of the variable in memory.

Learn more about Java

  • Get more quick code tips: Read all of Rafael's posts in the JavaWorld Java Challengers series.
  • Learn more about mutable and immutable Java objects (such as String and StringBuffer) and how to use them in your code.
  • Le sorprenderá saber que los tipos primitivos de Java son controvertidos. En esta función, John I. Moore argumenta a favor de conservarlos y aprender a usarlos bien.
  • Continúe desarrollando sus habilidades de programación Java en Java Dev Gym.
  • Si le gustó depurar la herencia de Java, vea más videos en la lista de reproducción de videos de Desafíos Java de Rafael (los videos de esta serie no están afiliados a JavaWorld).
  • ¿Quiere trabajar en proyectos sin estrés y escribir código sin errores? Diríjase a NoBugsProject para obtener su copia de Sin errores, sin estrés: cree un software que cambie la vida sin destruir su vida .

Esta historia, "¿Java pasa por referencia o pasa por valor?" fue publicado originalmente por JavaWorld.