Discussion:
Java básico: paso de parámetros por referencia
(demasiado antiguo para responder)
Jorge López
2004-05-04 20:38:20 UTC
Permalink
Buenas,
he empezado hace relativamente poco con Java y he encontrado mi
primera "duda existencial".

El caso es que aprendiendo a manejar listas me di cuenta de que al
cambiar la referencia de un objeto pasado como argumento a un método,
en el programa principal no cambiaba nada.

Así que hice alguna prueba con las clases de envoltura, como ejemplo
más sencillo. Algo como:

#v+
public class Paso {
public static void main (String [] args) {
Integer pepe = new Integer(3);
cambiamelo(pepe);
System.out.println("Vale: "+pepe);
}

public static void cambiamelo(Integer pepe)
{
Integer a = new Integer(10);
pepe = a;
}
}
#v-

Pues para mi sorpresa no cambia el valor ni por casualidad. Y esto es
lo que me choca, porque me enseñaron que java siempre hace el paso de
parámetros por referencia (en el caso de objetos) y por valor en el
caso de tipos primitivos. Por si fuera a servir de algo (un poco
de ilusión nunca viene mal) probé a hacer lo que se ve en el código,
a poner el mismo nombre del argumento que de la variable pasada,
aunque en condiciones normales no hubiera intentado tal cosa.

Para colmo, encuentro este documento de IBM:
http://www-106.ibm.com/developerworks/java/library/j-passbyval/

Viene a decir que java no tiene paso por referencia, que es un "mito"
que corre por ahí pero que para nada es así. Y pone unos ejemplos y
lo prueba.

Así pues, mi duda es: ¿realmente no existe el paso de parámetros por
referencia en java? ¿Para qué sirven entonces las clases de
envoltura? ¿Es que quizás hay alguna limitación en este paso de
parámetros (no se puede cambiar la referencia de un parámetro pero sí
usar métodos que modifiquen sus atributos)?

Muchas gracias y perdón por la duda tan básica, pero se me han caído
todos los esquemas.

Un saludín,

Jorge López
- --
/ _ _ _ / http://jorge.adirc.net
(_/()/ (/(- / jabber: ***@bulmalug.net
_/ / icq: 114276336
/
znôrt
2004-05-04 21:54:10 UTC
Permalink
On Tue, 04 May 2004 20:38:20 GMT, Jorge López
Post by Jorge López
#v+
public class Paso {
public static void main (String [] args) {
Integer pepe = new Integer(3);
cambiamelo(pepe);
System.out.println("Vale: "+pepe);
}
public static void cambiamelo(Integer pepe)
{
Integer a = new Integer(10);
pepe = a;
}
}
#v-
Pues para mi sorpresa no cambia el valor ni por casualidad. Y esto es
lo que me choca, porque me enseñaron que java siempre hace el paso de
parámetros por referencia (en el caso de objetos) y por valor en el
caso de tipos primitivos.
Eso es falso. O está mal expresado, y de ahí la confusión. 100 veces
hemos comentado esto aquí. A ver:
1. En java los argumentos siempre se pasan por valor. SIEMPRE.
2. Cuando el argumento es un objeto, lo que se pasa por valor es su
referencia.

Osea, en tu función cambiamelo(), tienes total acceso al argumento, ya
que lo que obtienes es una referencia al objeto. Ahora bien, como esa
referencia la obtienes por valor, lo que no puedes alterar es la
referencia en si, osea, la que tiene el llamador sobre el objeto. Es
decir, en tu ejemplo, cuando vuelvas de cambiamelo(), pepe seguirá
siendo el mismo objete pepe, impepinablemente, aunque cambiamelo() sí
podría haber cambiado su estado (sus atributos, por ejemplo). La única
posibilidad de obtener un nuevo "pepe" es como retorno de una función
o con new.
Post by Jorge López
Por si fuera a servir de algo (un poco
de ilusión nunca viene mal) probé a hacer lo que se ve en el código,
a poner el mismo nombre del argumento que de la variable pasada,
aunque en condiciones normales no hubiera intentado tal cosa.
Tal cosa es totalmente normal, e inocua, pero no creo que consiguieras
nada. :-)
Post by Jorge López
http://www-106.ibm.com/developerworks/java/library/j-passbyval/
Viene a decir que java no tiene paso por referencia, que es un "mito"
que corre por ahí pero que para nada es así. Y pone unos ejemplos y
lo prueba.
Pues tienen toda la razón :-). La verdad es que el mecanismo de Java
es muy sencillo. Creo que es un error de perspectiva más frecuente en
los que vienen de c++, que es otra guerra.

saludos
znôrt
Jorge López
2004-05-05 08:35:34 UTC
Permalink
Buenas,
Post by znôrt
Eso es falso. O está mal expresado, y de ahí la confusión. 100 veces
1. En java los argumentos siempre se pasan por valor. SIEMPRE.
2. Cuando el argumento es un objeto, lo que se pasa por valor es su
referencia.
[...] aunque cambiamelo() sí
podría haber cambiado su estado (sus atributos, por ejemplo). [...]
Me quedo con estos dos fragmentos, que son la clave del tema. Creo que
ya entendí que este paso "por referencia" no es tanto una referencia
total sino una copia del original que se puede modificar.

Gracias por la explicación, la verdad es que estuve buscando en
groups.google.com y vi varias preguntas como la mía, pero no me quedó
clara ninguna contestación.

Un saludín,

Jorge López
- --
/ _ _ _ / http://jorge.adirc.net
(_/()/ (/(- / jabber: ***@bulmalug.net
_/ / icq: 114276336
/
Jose Miguel
2004-05-04 21:48:00 UTC
Permalink
Hola, no estoy muy seguro, pero creo que la clave esta en que la
variable pepe del main no es la misma que la variable pepe de la
funcion, ya que has declarado la variable pepe dentro delo main y no
antes.
Ademas, fijate, que has declarado 2 veces la variable pepe, por
lo que cuando tu asignas a la variable pepe la direccion del objeto
que contiene a, realmente el pepe del main no cambia, pero el pepe de
dentro de la funcion si.

Escribe dentro de cambiamelo:

System.out.println("Vale: "+pepe);

y veras como ese si que cambia.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Buenas,
he empezado hace relativamente poco con Java y he encontrado mi
primera "duda existencial".
El caso es que aprendiendo a manejar listas me di cuenta de que al
cambiar la referencia de un objeto pasado como argumento a un método,
en el programa principal no cambiaba nada.
Así que hice alguna prueba con las clases de envoltura, como ejemplo
#v+
public class Paso {
public static void main (String [] args) {
Integer pepe = new Integer(3);
cambiamelo(pepe);
System.out.println("Vale: "+pepe);
}
public static void cambiamelo(Integer pepe)
{
Integer a = new Integer(10);
pepe = a;
}
}
#v-
Pues para mi sorpresa no cambia el valor ni por casualidad. Y esto es
lo que me choca, porque me enseñaron que java siempre hace el paso de
parámetros por referencia (en el caso de objetos) y por valor en el
caso de tipos primitivos. Por si fuera a servir de algo (un poco
de ilusión nunca viene mal) probé a hacer lo que se ve en el código,
a poner el mismo nombre del argumento que de la variable pasada,
aunque en condiciones normales no hubiera intentado tal cosa.
http://www-106.ibm.com/developerworks/java/library/j-passbyval/
Viene a decir que java no tiene paso por referencia, que es
un "mito"
que corre por ahí pero que para nada es así. Y pone unos
ejemplos y
lo prueba.
Así pues, mi duda es: ¿realmente no existe el paso de parámetros por
referencia en java? ¿Para qué sirven entonces las clases de
envoltura? ¿Es que quizás hay alguna limitación en este paso de
parámetros (no se puede cambiar la referencia de un parámetro pero sí
usar métodos que modifiquen sus atributos)?
Muchas gracias y perdón por la duda tan básica, pero se me han caído
todos los esquemas.
Un saludín,
Jorge López
- --
/ _ _ _ / http://jorge.adirc.net
_/ / icq: 114276336
/
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.2 (GNU/Linux)
iD8DBQFAl/81CNu8tzFvrGYRAoOLAJsGw/AuS14t81bPJGMMP+tnKFsE4QCcD6gO
ykn8xMWn6diDzCDWtZmI7GA=
=WGR3
-----END PGP SIGNATURE-----
--

ole
The Guevonaso
2004-05-04 22:08:09 UTC
Permalink
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Buenas,
he empezado hace relativamente poco con Java y he encontrado mi
primera "duda existencial".
El caso es que aprendiendo a manejar listas me di cuenta de que al
cambiar la referencia de un objeto pasado como argumento a un método,
en el programa principal no cambiaba nada.
Bueno, no te puedo contestar con argumentos teoricos porque no tengo la
base teorica adecuada, pero mas o menos creo que la cosa es algo asi,
segun mi forma de pensar y mis experiencias :

Todo se pasa por valor, si se pasa un tipo primitivo (int, boolean...) o
un objeto, el tipo y el "puntero" que apunta al objeto se "copian" (se
toma el valor). De forma que tu tienes en el metodo 'cambiamelo' un
"puntero" llamado pepe que apunta al mismo objeto que hiciste antes de
llamar al método (pepe y pepe' apuntan a Integer(3)) , pero luego,
dentro del método, hiciste que tu "copia" apuntase a otro sitio, (pepe'
y a apuntan al mismo integer(10) ) ....

No se si me he explicado. Quizas cambiando un poco tu ejemplo lo veas.
Así que hice alguna prueba con las clases de envoltura, como ejemplo
#v+
public class Paso {
public static void main (String [] args) {
Integer pepe = new Integer(3);
Aqui pepe apunta a un Integer(3)
cambiamelo(pepe);
System.out.println("Vale: "+pepe);
}
public static void cambiamelo(Integer Juan)
{
Juan "copia" el puntero pepe. Ambos apuntan a Integer (3)
Integer a = new Integer(10);
juan = a;
Juan ahora apunta a Integer (10) pero el objeto Integer (3) sige
existiendo y apuntado por pepe.
}
Prueba ahora esto a ver si asi lo ves mas claro, porque con Integer no
hay metodos para variarlo :


public class Prueba {
public static void main(String[] args) {
StringBuffer pepe = new StringBuffer("Soy Pepe");
cambiamelo(pepe);
System.out.println("Vale: " + pepe);
cambiamelo_2(pepe);
System.out.println("Vale: " + pepe);
}


public static void cambiamelo(StringBuffer pepe) {
pepe = new StringBuffer("cambio la copia");
}



public static void cambiamelo_2(StringBuffer juan) {
juan = juan.append(" Y me han cambiado ");
/*
* Observa como no he creado otro objeto, si no que he modificado el
* mismo usando la referencia que me han pasado
*/
}
}


No hagas esta prueba con String porque no va a funcionar. La razon es
que String cada vez que haces un "cadena"+"cadena" internamente crea
objetos nuevos (o algo asi).

Esta es la prueba que yo hice para aprender la diferencia.


Un saludo.

PD: perdon por la falta de formalismo, pero es que he tenido que
aprender por las bravas... y ya se sabe.
Jorge López
2004-05-05 09:35:33 UTC
Permalink
Buenas,
Post by The Guevonaso
Todo se pasa por valor, si se pasa un tipo primitivo (int, boolean...) o
un objeto, el tipo y el "puntero" que apunta al objeto se "copian" (se
toma el valor). De forma que tu tienes en el metodo 'cambiamelo' un
"puntero" llamado pepe que apunta al mismo objeto que hiciste antes de
llamar al método (pepe y pepe' apuntan a Integer(3)) , pero luego,
dentro del método, hiciste que tu "copia" apuntase a otro sitio, (pepe'
y a apuntan al mismo integer(10) ) ....
Creo que lo he entendido. Tengo un objeto al que apuntan dos
referencias, "la buena" y la "copia". Así que por mucho que yo
modifique la referencia "copia" no podré modificar la referencia
original, pero sí podré hacer uso de sus métodos y atributos puesto que
apuntan al mismo objeto. El ejemplo viene que ni pintado.

Muchas gracias. Un saludín,

Jorge López
- --
/ _ _ _ / http://jorge.adirc.net
(_/()/ (/(- / jabber: ***@bulmalug.net
_/ / icq: 114276336
/
P. Martinez
2004-05-05 10:47:44 UTC
Permalink
Prueba esto:

********************* INICIO *******************
public class Paso {

public static void main(String[] args) {
MiInteger pepe = new MiInteger(new Integer(3));
System.out.println("Vale: " + pepe);
cambiamelo(pepe);
System.out.println("Vale: " + pepe);
}

public static void cambiamelo(MiInteger sas) {
Integer a = new Integer(10);
//sas = new MiInteger( a );
sas.setInteger(a);
}
}

//Clase que sostiene un Integer.
class MiInteger {
private Integer val;

public MiInteger(Integer a) {
val = a;
}

public void setInteger(Integer a) {
val = a;
}

public Integer getInteger() {
return val;
}

public String toString() {
return val.toString();
}
}

********************* FIN *******************
http://www.myjavaserver.com/servlet/eurojet.shtml
________________________________________________
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Buenas,
he empezado hace relativamente poco con Java y he encontrado mi
primera "duda existencial".
El caso es que aprendiendo a manejar listas me di cuenta de que al
cambiar la referencia de un objeto pasado como argumento a un método,
en el programa principal no cambiaba nada.
Así que hice alguna prueba con las clases de envoltura, como ejemplo
#v+
public class Paso {
public static void main (String [] args) {
Integer pepe = new Integer(3);
cambiamelo(pepe);
System.out.println("Vale: "+pepe);
}
public static void cambiamelo(Integer pepe)
{
Integer a = new Integer(10);
pepe = a;
}
}
#v-
Pues para mi sorpresa no cambia el valor ni por casualidad. Y esto es
lo que me choca, porque me enseñaron que java siempre hace el paso de
parámetros por referencia (en el caso de objetos) y por valor en el
caso de tipos primitivos. Por si fuera a servir de algo (un poco
de ilusión nunca viene mal) probé a hacer lo que se ve en el código,
a poner el mismo nombre del argumento que de la variable pasada,
aunque en condiciones normales no hubiera intentado tal cosa.
http://www-106.ibm.com/developerworks/java/library/j-passbyval/
Viene a decir que java no tiene paso por referencia, que es un "mito"
que corre por ahí pero que para nada es así. Y pone unos ejemplos y
lo prueba.
Así pues, mi duda es: ¿realmente no existe el paso de parámetros por
referencia en java? ¿Para qué sirven entonces las clases de
envoltura? ¿Es que quizás hay alguna limitación en este paso de
parámetros (no se puede cambiar la referencia de un parámetro pero sí
usar métodos que modifiquen sus atributos)?
Muchas gracias y perdón por la duda tan básica, pero se me han caído
todos los esquemas.
Un saludín,
Jorge López
- --
/ _ _ _ / http://jorge.adirc.net
_/ / icq: 114276336
/
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.2 (GNU/Linux)
iD8DBQFAl/81CNu8tzFvrGYRAoOLAJsGw/AuS14t81bPJGMMP+tnKFsE4QCcD6gO
ykn8xMWn6diDzCDWtZmI7GA=
=WGR3
-----END PGP SIGNATURE-----
Loading...