đŸ’©

programierds

PROGRAMIERDS_OS v1.0.4 // TOPIC: JAVA_MEMORY

> Paso por Valor

y Referencia

En Java, todo se pasa por valor. Pero no es tan simple como suena.

VALOR
copia directa
REFERENCIA
dirección de memoria

↓ scroll para continuar


FUNDAMENTO

Stack vs Heap

Primero entendé cómo Java organiza la memoria. Sin esto, nada de lo que viene tiene sentido.

STACK

Variables locales y referencias. LIFO.

int x 42
boolean b true
int[] nums → 0x4A2F
Persona p → 0x8C1D

Primitivos: el valor vive acá.
Objetos: solo la dirección (referencia).

HEAP

Objetos reales. Gestionado por el GC.

0x4A2F
int[ ]
[ 1, 2, 3 ]
0x8C1D
Persona
nombre: "Ana"
0x3F0B
String
"Hola"

Los objetos reales viven acá.
El Stack guarda la dirección para llegar.

LA REGLA FUNDAMENTAL

Cuando Java "pasa" algo a un método, lo que viaja es el contenido de la casilla del Stack. Para primitivos eso es el valor directo. Para objetos eso es la dirección de memoria (la referencia). En AMBOS casos: se copia.


CASO 01

Paso por Valor

Con primitivos (int, double, boolean, char...)

void cambiar(int x) {
  x = 99;
  // x es una COPIA local
}

int a = 5;
cambiar(a);
System.out.println(a); // 5 ← no cambió

POR QUÉ

Java copia el valor 5 en una nueva variable x. Cualquier cambio a x es local al método. a nunca se toca.

VISUALIZACIÓN

a
5
───> copia
x (copia)
5

x cambia a 99...

...pero a sigue siendo 5  


CASO 02 — EL TRICKY

Objetos: La Referencia se Copia

Ambas variables apuntan al MISMO objeto en el heap

void modificar(int[] arr) {
  arr[0] = 99;
  // arr apunta al MISMO objeto
}

int[] nums = {1,2,3};
modificar(nums);
System.out.println(nums[0]); // 99!

POR QUÉ

arr recibe una COPIA de la referencia (la dirección 0x4A2F). Ambas apuntan al mismo array en el heap. Modificar arr[0] modifica el objeto real, y nums lo ve.

DIAGRAMA DE MEMORIA

STACK
nums → 0x4A2F
arr (copia) → 0x4A2F
HEAP
0x4A2F
[ 1, 2, 3 ]
arr[0] = 99 → nums[0] == 99

CASO 03 — LA PRUEBA

Reasignar la Referencia

Esto prueba QUE Java pasa referencias por valor

void reasignar(int[] arr) {
  arr = new int[]{99,99,99};
  // arr ahora apunta a OTRO objeto
  // nums NO se entera
}

int[] nums = {1,2,3};
reasignar(nums);
System.out.println(nums[0]); // 1 ← no cambió

LA CLAVE

arr = new int[]... solo cambia a dónde apunta la COPIA local. La referencia original nums en el Stack del llamador no se modifica. Sigue apuntando al objeto original. Esta es la prueba de que Java pasa referencias POR VALOR.

DIAGRAMA

STACK
nums → 0x4A2F
arr (copia) → 0x4A2F
HEAP
0x4A2F
[1, 2, 3]
← nums apunta acá
0x9E3C
[99,99,99]
← arr reasignado
nums[0] sigue siendo 1

CASO 04

Clase Persona

Modificar campos vs reasignar el objeto

✓ Modifica el campo

class Persona {
  String nombre;
}

void cambiarNombre(Persona p) {
  p.nombre = "Nuevo";
}

Persona ana = new Persona();
ana.nombre = "Ana";
cambiarNombre(ana);
// ana.nombre == "Nuevo" ✓

RESULTADO

p apunta al mismo objeto que ana. Modificar p.nombre cambia el objeto compartido.

✗ Reasigna la referencia

void reemplazar(Persona p) {
  p = new Persona();
  p.nombre = "Otro";
  // p apunta a un objeto nuevo
}

Persona ana = new Persona();
ana.nombre = "Ana";
reemplazar(ana);
// ana.nombre == "Ana" (sin cambios)

RESULTADO

La copia local p apunta a otro objeto. ana sigue apuntando al original.


CASO ESPECIAL

Strings son Inmutables

En Java, String es un objeto especial. Jamás cambia. Siempre crea uno nuevo.

void cambiar(String s) {
  s = "Nuevo";
  // Esto crea un NUEVO String
  // s ahora apunta al nuevo objeto
}

String nombre = "Ana";
cambiar(nombre);
System.out.println(nombre); // "Ana"

INMUTABILIDAD

String en Java es inmutable por diseño. s = "Nuevo" NO modifica el String existente. Crea un objeto nuevo en el heap y apunta la variable local a él.

STRING POOL

Los strings literales van al String Pool (área especial del heap). Usá .equals() para comparar contenido, nunca ==.

QUÉ PASA EN MEMORIA

STACK
nombre → 0xA1B2  ✓
s (copia) → 0xC3D4 (new)
HEAP
0xA1B2 (String Pool)
"Ana"
original, inmutable
0xC3D4
"Nuevo"
objeto nuevo
nombre sigue siendo "Ana"

SNAPSHOT

Diagrama de Memoria Completo

Todo junto. Primitivos y referencias en acción.

STACK
int edad 25
double sueldo 3500.0
boolean activo true
String nombre → 0xA1B2
int[] scores → 0x4A2F
Persona p → 0x8C1D
primitivos: valor directo   objetos: dirección
HEAP
0xA1B2
String
"Ana"
0x4A2F
int[]
[90, 85, 78]
0x8C1D
Persona
nombre: → 0xA1B2
edad: 25

Los objetos no viven en el Stack.
Solo la dirección para encontrarlos.

NOTA SOBRE PRIMITIVOS

Los primitivos (int, double, boolean, char, long, float, short, byte) son los ÚNICOS que viven directamente en el Stack. Todo lo demás — incluyendo String, arrays y cualquier clase custom — vive en el Heap.


SÍNTESIS

Reglas de Oro

Grabátelas. Son inamovibles.

01

Java SIEMPRE pasa por valor

Sin excepciones. No existe "paso por referencia" en Java.

02

Para primitivos: se copia el VALOR

El método recibe una copia. Cambiarla no afecta al original.

03

Para objetos: se copia la REFERENCIA

La copia contiene la misma dirección de memoria. Ambas apuntan al mismo objeto.

04

Modificar el objeto a través de la copia: SÍ afecta al original

arr[0] = 99, p.nombre = "X" — ambas referencias ven el cambio.

05

Reasignar la referencia copiada: NO afecta al original

arr = new int[]..., p = new Persona() — solo mueve la copia local.


ESTADO: SESION_COMPLETADA

SESION FINALIZADA

Ahora sabés la diferencia entre paso por valor y referencia en Java.
No la vayas a confundir con "paso por referencia" de otros lenguajes.

PRIMITIVOS

int, double, boolean, char, long, float, short, byte

→ copia del valor

OBJETOS

String, arrays, cualquier clase

→ copia de la referencia

FIN DE SESION // DATOS PROCESADOS CORRECTAMENTE

← VOLVER A PRESENTACIONES