Mundo Byte

Acercando el conocimiento de TI en términos sencillos

Parámetros en Java: ¿Valor o Referencia?

Hoy revisando algunos libros de Java, me encontré con algunos en donde sorprendentemente dicen una GRAN mentira. De hecho, muchos sitios en internet manejan que el paso de parámetros en Java se hace de dos formas:

  1. Si se tratan de tipos primitivos como int, double, etc. el paso se da por valor o copia.
  2. Si se tratan de Objetos (en realidad son referencias a objetos) entonces el paso de valor se hace por referencia.

NO hay nada más equivocado que esta idea, lo lamentable es que incluso sean los autores de libros, los “conocedores” y expertos de la materia los que caigan en tan infantil error. Uno de los autores de los que hablo es un Español muy conocido cuyo nombre empieza con F…. otro autor que me parece es mexicano y si bien recuerdo es de la misma editorial que el primer autor que menciono y cuyo apellido también empieza con la letra F afirma del mismo modo que Java hace el paso de parámetros por referencia y cuyo libro/tutorial esta pegado en la página de un Instituto Tecnológico de aqui en México.

Y bueno ni se digan de varias páginas en donde se habla de lo mismo, por ejemplo: http://es.wikibooks.org

En fin, encontré un artículo que me parecio interesante: http://jpangamarca.wordpress.com/cafe-java/en-java-el-paso-de-parametros-es-por-valor/

donde desmiente ese mito de que Java hace el paso de parámetros por Referencia, dejando en claro que únicamente se hace por VALOR.

Si alguno tiene dudas sobre este tema de las Referencias de Objetos, comentela aqui y en la medida de mi tiempo trataré de brindarle alguna explicación.

 

NOTA DEL DÍA 29 DE JUNIO DEL 2009.

Dada la discución y confusión que existe en los comentarios de este tema, escribi un artículo dividido en tres partes en donde demuestro de forma contundente que Java no realiza un paso de parámetros por referencia.

Espero que con esto, quede aclarado todo este tema. Principalmente hubieron algunas personas que me acusaron de no tener idea de lo que digo :D … pero bueno, este artículo les demuestra lo contrario.

http://mundobyte.wordpress.com/2009/06/29/i-paso-de-parmetros-en-java-por-valor/

Saludos!!

25 Responses to Parámetros en Java: ¿Valor o Referencia?

  1. ignorante abril 7, 2008 a las 1:22 pm

    Bueno, depende como se lo interprete. Los objetos sí se pasan por referencia, lo que se pasa por valor es la referencia al objeto.

    Igual estyo de acuerdo en que es bueno aclarar todo eso y no dar una visión parcial que puede llevar a confusiones.

  2. windoctor abril 7, 2008 a las 3:26 pm

    Cuando se pasa un parámetro a otro método se hace una copia de la referencia y NO se le pasa la dirección de memoria (que es a lo que llamamos paso por referencia), pues si esto ultimo fuera verdad el siguiente método modificaria el valor original…

    public static void intercambiar(Empleado x, Empleado y)
    {
    Empleado temp = x;
    x = y;
    y = temp;
    }

    ……
    Empleado a = new Empleado(“Alicia”….);
    Empleado b = new Empleado(“Benito…);
    intercambiar(a,b)

    ¿Se refiere ahora “a” a Benito y b a alicia?… NO

    Pero como se trata de una COPIA de la referencia al objeto, unicamente se modifica la copia y no el original. SI se tratara de un paso por referencia, ambos serían el mismo objeto en si, por lo cual, al tratar de referenciar:

    x = y …. entonces también “temp” apuntaria al mismo objeto y por lo cual si habría una modificación al objeto original.

    saludos!!

    • Erwin junio 2, 2009 a las 4:17 am

      Ja…, yo creía lo mismo de que solo era paso por valor. Pero que gran mentira y ese artículo si que es una farsa. Acomodado y utilizando objetos diferentes para confundir. La realidad es que JAVA si permite paso por referencia. Es puro manejo de punteros. Solo en los tipos primitivos y String en el paso de argumentos a métodos se maneja el paso por valor…, para cualquier otro objeto que no sea String se pasa es la referencia, ósea se le asigna el valor de la referencia a otra referencia. Ambas quedan apuntando al mismo objeto y con la segunda puedo modificar el objeto…, Según el mismo principio que allí explican eso es paso por referencia…, Y lo debato con quien sea…

      • japones junio 7, 2009 a las 5:10 am

        SI quiere debatirlo con quien sea, usted debe ser más inteligente que el mismo
        James GOsling creador del lenguaje Java, quien realmente afirma que java
        sol tiene un paso de parámetros, y es por valor….

        Será que habrá que comparar curriculums para creer que usted es mejor y
        tiene la razón??

      • Francisco Chávez febrero 16, 2012 a las 1:36 am

        Perdón, son principiante en java, pero tengo entendido que no maneja punteros.

  3. Juan Pablo Angamarca mayo 18, 2008 a las 4:30 am

    Gracias por referenciar mi artículo. Saludos.

  4. martin javier castellanos mayo 21, 2008 a las 6:57 pm

    he leido este articulo pero en parte tienen razon pero por otra parte están en un error fatal, pues es asi como lo aprecio y les dire el por qué.

    windoctor, segun el link y primer comentario, afirma que los objetos se pasan por valor y no por referencia.
    si observa el metodo…
    10 public static void cambiarObjeto(ValorOReferencia objeto) {
    11 objeto = new ValorOReferencia(”Este es un nuevo objeto.”);
    12 System.out.println(”Luego de \”reasignar\” pass: ” + objeto);
    13 }
    en la linea 10, el método crea una variable “objeto” de tipo “ValorOReferencia” que apunta precisamente a la misma dirección de memoria. Dicha direccion de memoria (pass=direccion de memoria xyz, objeto=direccion de memoria xyz).
    Pero NOTESE que en la linea 11 asignamos con la funcion “new” una nueva direccion de memoria a la que apuntara “objeto”, por lo cual, a partir de este momento, objeto y memoria ya no apuntan a la misma direccion de memoria.
    Concluyo que NO ES VALIDO el tratar de afirmar que los parametros de objetos se hacen por VALOR.

    Con respecto a tu segundo comentario, windoctor, ese ejemplo me indica que tienes un concepto erroneo de como funcionan internamente los objetos, es decir, que sucede en memoria al declarar una variable de tipo “clase” y que sucede en memoria cuando se le aplica la funcion “new” a ese objeto.
    Al declarar una variable de tipo “clase”, en memoria reserva una localidad de memoria para almacenar en ella un valor que hace referencia a otra localidad de memoria.
    Cuando se aplica un “new” sobre una variable instanciada (“objeto”) de una clase, en memoria se reserva el tamaño del objeto para almacenar los valores de las propiedades del objeto, el cual sera referenciado por dicha variable instanciada (“objeto”).
    Analiza tu ejemplo bajo la siguiente suposicion de direcciones de memoria:
    “a” apunta a la dir. de mem. #AA
    “b” apunta a la dir. de mem. #BB
    El método intercambiar, al ser invocado, declara dos variables del mismo tipo que “a” y “b” llamadas “x” y “y”. Por lo tanto, “x” apunta a la dir. de mem. #AA y “y” apunta a #BB.
    La línea de “Empleado temp=x” hace lo siguiente: en memoria se reserva una localidad de memoria para “x” la cual almacenará una dir. de mem. que corresponde a un objeto de tipo “Empleado”; es decir, “temp” apunta a la dir. de mem. #AA.
    “x=y” hace que “x” apunte a la dir. de mem. #BB
    “y=temp” hace que “y” apunte a la dir. de mem. #AA, y al terminar el método, elimina la variable “temp” pero no el objeto, debido a que la dir. de mem. que tenía almacenada (#AA) esta referenciada por el objeto “y”.

    Ojo: “Asignación de objetos” no implica copiar las propiedades del objeto, solo implica que se asigna la misma referencia de mem. a la asignación de variable.

  5. windoctor mayo 21, 2008 a las 9:53 pm

    De hecho y sin crear polèmica, me parece que en lo personal yo aprecio en usted na confusión incluso entre lo que es una clase y un objeto asi como su representacion en memoria.

    EL ejemplo que comentè, es del LIbro de Core Java de los autores Cay S. Horstmann y Gary Cornel, ambos cientificos respetables y consultores de Tecnologia Java.

    EN su libro tratan todo este tema que merece la pena analizar.

    LO malo que no tengo mucho tiempo de momento.

    saludos!

  6. IGNORANTE julio 14, 2008 a las 4:01 am

    windoctor ………claramente estas hablando de algo que poco o nada entiendes.

  7. RoHer noviembre 8, 2008 a las 6:23 pm

    Hola!!!
    Siguiendo su caso les quería comentar lo siguiente:
    Definitivamente, cuando pasamos por parámetro un Objeto (Java), lo que pasa por valor es la dir. de memoria en donde esta alojado el mismo.
    O sea el metodo “intercambiar(….)” antes mencionado, intercambia las referencias de las instancias pasadas por valor, pero al terminar la ejecución del metodo y volver al contexto de ejecución que invocó al metodo, los objetos que fueron como parametros del metodo “intercambiar(….)”, tendrán las dir. de memoria originales.

    Saludos.

    Les dejo un ejemplo:

    /** Ejemplo —- Class**/

    package oracle.tasa.pgc;

    public class MemTest {

    public class BaseIdDescDTO{
    private String description;

    public BaseIdDescDTO() {
    super();
    // TODO Auto-generated constructor stub
    }

    public String getDescription() {
    return description;
    }

    public void setDescription(String description) {
    this.description = description;
    }

    }

    public BaseIdDescDTO getBaseInstance(){
    return new BaseIdDescDTO();
    }

    public static void main(String []args){
    BaseIdDescDTO b1 = new MemTest().getBaseInstance();
    BaseIdDescDTO b2 = new MemTest().getBaseInstance();
    b1.setDescription(“1111″);
    b2.setDescription(“2222″);
    System.out.println(“contenido antes: ” + b1.getDescription() + “, ” + b2.getDescription());
    cambio(b1, b2);
    System.out.println(“contenido despues: ” + b1.getDescription() + “, ” + b2.getDescription());
    }

    public static void cambio(BaseIdDescDTO x, BaseIdDescDTO y){
    BaseIdDescDTO temp = x;
    x = y;
    y = temp;
    y.setDescription(“3333″);
    }
    }
    /** Fin class **/

    __ Obtendrán como salida:

    “contenido antes: 1111, 2222″
    “contenido despues: 3333, 2222″

  8. Nelson Guerra Alvarez junio 26, 2009 a las 8:54 pm

    Windoctor. Dejame decirte que estas totalmente equivocado. Java si pasa parametros por referencia.
    Tu haces referencia a
    “En fin, encontré un artículo que me parecio interesante: http://jpangamarca.wordpress.com/cafe-java/en-java-el-paso-de-parametros-es-por-valor/“.
    Dejame decirte que Juan Pablo Angamarca (el creador del articulo) no posee los conocimientos necesarios de Java, y si lees detalladamente el ejemplo te daras cuenta que en el ejemplo se describe exactamente el paso de parametros por referencia no por valor.
    Lo que sucede es que tanto tu como Juan Pablo Angamarca parecen no haber trabajado nunca con el lenguaje C o C++, en donde se utilizaban punteros. los conocedores de estos lenguajes saben de lo que hablo, y sabran que Java viene de C y C++ y solo coloco una capa mas para manejar los punteros, para que los programadores no puedan apuntar a lugares que no corresponde (ya sea por que cometieron un error o no).

  9. windoctor junio 29, 2009 a las 3:16 am

    HOLA A TODOS!

    DADA LA DISCUCIÓN Y CONFUSIÓN EXISTENTE EN ESTE TEMA, HE DECIDIDO ESCRIBIR UN ARTÍCULO DEMOSTRANDO EL ERROR QUE TIENEN MUCHOS AL PENSAR QUE JAVA HACE UN PASO DE PARÁMETROS POR REFERENCIA.

    DIVIDO EL ARTÍCULO EN 3 PARTES, EN LA TERCERA PARTE PONGO REFERENCIAS REALES DE AUTORES QUE DESMIENTEN ESTE ERROR.

    PRINCIPALMENTE PARA AQUELLOS QUE COMENTARON HACIA MI PERSONA DICIENDO QUE NO TENGO IDEA DE LO QUE HABLO, ESTE ARTÍCULO LES DEMOSTRARÁ EL ERROR EN EL QUE ESTAN.

    SALUDOS!!

  10. Ko-Barde mayo 17, 2010 a las 2:10 pm

    Juan Pablo, gracias por una explicación tan detallada.

    Creo que la forma tan purista de explicarlo puede haber causado cierta confusión a los seguidores de java mas prácticos.

    Intentaré no liarlo mas y reitero mi agradecimiento por tu esfuerzo y los gráficos tan claros:

    En java todo son punteros, sólo que no hay necesidad de emplear la aritmética que hay en C para los mismos, en Java todo eso es automático.

    Pasemos lo que pasemos como parámetro a una función, esta recibe una copia del puntero del parámetro, es decir, que los punteros son pasados por valor. Esto para Java no es relevante.

    Cuando el parámetro que se pasa es un tipo primitivo (int, double, boolean) lo que se pasa es un puntero a una copia de su espacio de memoria, es decir, dentro de la función se trabaja la copia (el efecto es equivalente al de pasar el parámetro por valor).

    Cuando el parámetro es un objeto, se pasa una copia del puntero al objeto (sin clonar el espacio de memoria del objeto, que sería un derroche de la misma y de tiempo de CPU), es decir, dentro de la función se trabaja sobre el espacio de memoria del objeto, actuando sobre el contenido del objeto (el efecto es equivalente al de pasar el parámetro por referencia).

    Espero haber sido de ayuda

  11. Edgar agosto 3, 2011 a las 4:05 am

    Hola a todos no tengo conocimientos tan profundos como ustedes y no voy a comentar sobre el tema tan interesante que estaban debatiendo, pero me interesó en la parte del comentario de “martin javier castellanos” que dice asi: “..que sucede en memoria al declarar una variable de tipo “clase” y que sucede en memoria cuando se le aplica la funcion “new” a ese objeto.”, si pudieran profundizar mas al respecto de como trabaja la memoria con las clases y sus instancias, o informarme sobre algun sitio.

    Salu2!!

  12. Java Tutorial septiembre 8, 2011 a las 8:49 am

    De la web oficial de Oracle(antes Sun):
    http://download.oracle.com/javase/tutorial/java/javaOO/arguments.html (2 últimos apartados)

    Resumiendo:
    Tipos primitivos => paso por valor
    Objetos => paso por referencia.
    Hay que aclarar que dice, que lo que se pasa por valor es “la referencia del objeto (digamos que el puntero), se modifica el objeto y se devuelve ya modificado, pero no puedes reasignar(utilizar new) la variable del objeto (objeto =new Claseprueba() – ESTE CAMBIO DESAPARECERA AL TERMINAR EL METODO, apuntando de nuevo al objeto anterior)

    • rr7 octubre 15, 2011 a las 7:22 pm

      Java Tutorial: vaya forma de tergiversar las cosas. Citado del enlace que tú mismo pones:

      “Reference data type parameters, such as objects, are also passed into methods BY VALUE.” (énfasis mío)

      Lo que dice el texto citado es que, como es sabido, los objetos en Java se manipulan únicamente a través de referencias. Son “tipos de datos de referencia”, que se pasan, como cualquier otro tipo en Java, por valor. Estás confundiendo “tipo de dato” con “forma en que ese dato se pasa a las funciones”.

      Así que los objetos se pasan por valor. Y ya lo demuestra muy bien escom.alex

  13. escom.alex octubre 5, 2011 a las 5:17 pm

    Estoy de acuerdo con windoctor, Java hace paso por valor, es decir cuando se trabaja con objetos y se pasa la referencia a una función, se crea una copia (de la referencia) la cual también puede modificar el mismo objeto (dentro del ámbito de la función) com el ejemplo de RoHer, pero las referencias se mantiene intactas después de invocar a la función.Volvemos al mismo ejemplo, listo para compilar y probar.

    import java.lang.String;

    public class C
    {
    String s;

    C(){}

    C(String s){ this.s = s; }

    public String toString(){ return s;}

    public static void inter(C uno, C dos)
    {
    C temp = uno;
    uno = dos;
    dos = temp;
    }

    public static void main(String[] args)
    {
    C uno = new C(“UNO”);
    C dos = new C(“DOS”);
    System.out.println(“Antes de intercambiar”);
    System.out.println(“1.- ” + uno);
    System.out.println(“2.- ” + dos);
    C.inter(uno,dos);
    System.out.println(“Despues de intercambiar”);
    System.out.println(“1.- ” + uno);
    System.out.println(“2.- ” + dos);
    }
    }

    Como se puede apreciar aún cuando se intercambian las referencias dentro de la funcion “inter” la salida sigue siendo:

    Antes de intercambiar
    1.- UNO
    2.- DOS
    Despues de intercambiar
    1.- UNO
    2.- DOS

    Obvio, si dentro de la funcion inter (cuando los apuntadores temporales cambian de objeto referenciado) se modifica algún dato del objeto éste se verá afectado fuera de la función, ya que el objeto al que apuntan sigue siendo el mismo.

  14. escom.alex octubre 5, 2011 a las 5:27 pm

    Nota:
    Para aquellos que vayan a empezar a refutar esto, pueden modificar la función:

    public static void inter(C uno, C dos)
    {
    C temp = uno;
    uno = dos;
    dos = temp;
    System.out.println(“Dentro con referencias temporales”);
    System.out.println(“1.- ” + uno);
    System.out.println(“2.- ” + dos);
    }

    Salida:

    Antes de intercambiar
    1.- UNO
    2.- DOS
    Dentro de inter con referencias temporales
    1.- DOS
    2.- UNO
    Despues de intercambiar
    1.- UNO
    2.- DOS

    Touché !

  15. Jorge Chayan noviembre 11, 2011 a las 2:49 am

    Amigo Autor Estas Es GRAN equivocado, no hay que llegar a los objetos… En Arreglos: Como es Que Al Aplicar Un Bubblesort A Un Arreglo Desde Un Metodo Externo, Modifica El Orden Del Arreglo Que Fue Pasado Como Parametro?? Lo Hace Por Referencia Amiguito!

  16. pepe@pepe.com noviembre 21, 2011 a las 4:41 pm

    Sois todos unos ignorantes. Estoy de acuerdo con windoctor. ¿Es que nadie más sabe lo que es un paso por referencia? ¿O es que no habéis probado a ejecutar el código y ver lo que hace?. Los objetos también se pasan por valor, por mucho que digáis que lo que se pasa por valor es la dirección del puntero (ya no sería paso por valor sino por referencia) no va a ser así. Dejad de confundir a la gente.

    Estoy harto de tanto ignorante. Antes de publicar leer, informaros y probad, sobre todo probad lo que decís.

    En definitiva, gracias windoctor por hacer bien las cosas.

  17. Igor diciembre 15, 2011 a las 11:01 pm

    ¿Cuántos de aquellos que afirman que los parámetros se pasan por referencia son en realidad programadores Java? Y no vale haber hecho un “Hello world!”…

    Pongo un enlace, para quienes entiendan inglés, a una página que es para quienes la conocen lo más parecido a la Biblia (versión Java) que se puede encontrar en Internet:

    http://stackoverflow.com/questions/1068760/can-i-pass-parameters-by-reference-in-java

    Por cierto, me hace gracia el comentario de escom.alex: “Dentro de inter con referencias temporales”. No está mal, se ha inventando las “referencias temporales” con tal de no dar la razón al autor y llamarlo con su nombre: paso por valor.

  18. Jazumaru abril 24, 2012 a las 3:47 am

    import java.io.*;
    class prueba{

    public static void main(String args[]){
    int j[];
    j= new int[5];
    prueba.rt(j);

    for (int i=0;i<j.length;i++)
    System.out.println(j[i]);
    }

    public static void rt(int h[])
    {
    //en esta funcion se asignan los valores a la variable j que se declaro en main
    int e;
    for (int i=0;i<h.length;i++)
    {
    e=i*2;
    h[i]=e;
    }

    }
    }

    Alguien me podria explicar esto porque a mi me parece que pasa arreglos y objetos por referencia

  19. Raúl mayo 22, 2012 a las 1:48 pm

    Ké follón tenéis! Madre mía!
    Lo primero ke yo diría es ke si no sois ingenieros en ciencias de la computación, por favor no habléis, ke lo único ke hacéis es liar a la gente.

    Todos sin kererlo estáis diciendo lo mismo. A ver, Java no es C++ (ya le gustaría tener el mismo potencial), no existen los punteros, con lo cual ya no se puede hablar de apuntadores a direcciones, aunke claro ke los maneja internamente. Entonces vamos al paso de parámetros. Os habéis cegado en el término en sí, y ya sabéis ke nuestro lenguaje es ambiguo, llamadle como keráis mientras sepáis lo ke hace. Pero al no haber punteros, yo personalmente no hablaría de paso por referencias, ya ke nunca podremos hacer algo del estilo: “function(type& var);”. Por otro lado si nuestro lenguaje es ambiguo (los ke han hecho IA saben a lo ke me refiero), hacedle caso al padre de Java “Gosling is generally credited with having invented the Java programming language in 1994″ ke dice en su libro “There is exactly one parameter passing mode in Java – pass by value – and that helps keep things simple.”

    Saludos a todos y gracias al autor por este post.

Deja un comentario

Fill in your details below or click an icon to log in:

Logo de WordPress.com

You are commenting using your WordPress.com account. Log Out / Cambiar )

Twitter picture

You are commenting using your Twitter account. Log Out / Cambiar )

Facebook photo

You are commenting using your Facebook account. Log Out / Cambiar )

Connecting to %s

Seguir

Get every new post delivered to your Inbox.

Únete a otros 187 seguidores