Paso de variables por Valor y por Referencia en Java

23 de enero 2009
Tags: ,

En el paso de parámetros de variables a métodos en Java se suele decir que:

  • las variables de tipo simple (int, double, etc) se pasan por valor
  • los objetos se pasan por referencia.

Ésto no es cierto, después de consultar varias fuentes puedo concluir que en Java las variables, ya sean simples u objetos, se pasan siempre por valor.

El hecho de hacernos pensar que los objetos se pasan por referencia se debe a que si pasamos un objeto a un método y modificamos su valor dentro del método, al salir de éste, nuestro objeto habrá sido modificado.
Pero nosotros en realidad no hemos pasado el objeto como tal, sino que hemos pasado por valor la referencia al objeto, es decir, le hemos pasado una copia de su dirección en memoria.

Por lo tanto, cuando pasamos un objeto a un metodo, siempre estaremos pasando una copia de su dirección, por lo que aunque le cambiemos la direccion, en cuanto salga del metodo, volverá a tener la dirección original. Sin embargo, si dentro del método accedemos a su contenido y lo modificamos, éste si que seguirá modificado una vez salgamos del método, porque el contenido no es ninguna copia.

Para que se entienda mejor, podéis probar ésto:



   import java.awt.Point;
   class PassByValue
   {
     public static void modifyPoint(Point pt, int j)
     {
        pt.setLocation(5,5);                                      //1
        j = 15;
        System.out.println("During modifyPoint " + "pt = " + pt +
                           " and j = " + j);
     }
     public static void main(String args[])
     {
        Point p = new Point(0,0);                                 //2
        int i = 10;
        System.out.println("Before modifyPoint " + "p = " + p +
                           " and i = " + i);
        modifyPoint(p, i);                                        //3
        System.out.println("After modifyPoint " + "p = " + p +
                           " and i = " + i);

     }
   }


  

Que dará de salida esto:


Before modifyPoint p = java.awt.Point[x=0,y=0] and i = 10
During modifyPoint pt = java.awt.Point[x=5,y=5] and j = 15
After modifyPoint p = java.awt.Point[x=5,y=5] and i = 10

13 Comentarios

  1. KURAGARi

    Y si lo que quieres es poder cambiar el contenido de un tipo básico como el bolean, el int o el String dentro de un método (lo que en C# se hace añadiendo un “ref” que preceda la declaración del parámetro o el & de C/C++) como lo harías?

    23 de febrero, 2009 a las 2:38 pm
  2. Jose Dueñas

    @KURAGARi: de una forma directa como en C no se puede ya que como dijimos Java siempre pasa por valor los tipos básicos.
    Una posible solución pasaría por “camuflar” ese tipo básico en un objeto.
    Por ejemplo, pasariamos como argumento un array que contendria solamente a éste tipo básico para poder modificarlo sin problema.
    Veámoslo con ujemeplo en el que cambiamos una variable de tipo int:

    public static void modificarVariable(int [] array)
    {
    array[0] = 99; //mi nuevo valor sera 99
    }

    public static void main(String args[])
    {
    int[] miVariable = { 1 };
    modificarVariable(miVariable);
    System.out.println("El nuevo valor de mi variable es: " + miVariable[0]);
    }

    De todos modos es poco elegante y se debería evitar ésta práctica.

    Un saludo

    23 de febrero, 2009 a las 10:17 pm
  3. Mariano

    Lo que dice KURAGARi no es posible debido a que Java, a diferencia de C*, no permite trabajar con punteros. Para hacer lo que tu dices es necesario poder manejar punteros a memoria

    10 de marzo, 2009 a las 4:06 am
  4. Franco

    Mas elegante seria instanciar una clase wrapper de integer, por ejemplo: Integer nro = new Integer(3);
    Y luego llamas al metodo y modificas su (estado) valor como quieras.

    22 de abril, 2009 a las 6:37 am
  5. Jose Dueñas

    Hola Franco,
    efectivamente, pero se trataba de ver cómo hacerlo para variables de tipo simple, no objetos. Ya sabemos que los objetos se pasan siempre por referencia.

    22 de abril, 2009 a las 9:12 am
  6. Gonzalo

    Sin embargo los tipos basicos encapuslados (Integer, Character, etc) no pueden modificar su valor, asi que tampoco vale pasar un Integer.
    Parece que el array es la mejor opcion, a fin de cuentas un array de un elemento no es mas que un puntero a ese elemento ;)

    2 de julio, 2009 a las 8:25 pm
  7. robertito

    Buenas,
    me he encontrado con un pequeño problema referente a todo esto…. tengo un objeto y quiero crear otro igual, pero OTRO. si hago
    Objeto a = new Objeto();
    Objeto b = a;
    si modifico b, tambien se modifica a. como podria evitar esto? crear una copia de este objeto, y no crear otra referencia al mismo objeto?
    muchas gracias…

    19 de agosto, 2009 a las 8:08 pm
  8. Miguel Vegallero

    Robertito, fácilmente:

    Objeto a = new Objeto(); // Se crea el objeto a
    .
    . // Se modifica el objeto a
    .
    Objeto b = new Objeto(a); // Se crea el objeto b, que es clon de a

    17 de septiembre, 2009 a las 3:05 am
  9. Juan

    Saludos Jose, mi duda es si dices que en java las variables simples u objetos se pasan simpre por valor, porque en tu segundo comentario dices “Ya sabemos que los objetos se pasan siempre por referencia.”. me podrias aclarar eso por favor. Gracias

    24 de octubre, 2009 a las 11:12 pm
  10. Jose Dueñas

    Hola Juan,
    si, en realidad quería decir que se pasa por valor la referencia al objeto (su dirección).

    25 de octubre, 2009 a las 1:07 am
  11. CESARS

    Hola, tengo una pregunta, es que nececito cambiar una variable de tipo int a String, y despues de convertirla mostrarla en una textfield.
    asi voy en el momento.

    String dato,resultado;//variables
    int intdato,intresultado;//variables

    dato= textField.getString();//tomo el valor del texField
    intdato=Integer.parseInt(dato);//aqui cambio la variable string a entero
    intresultado = intdato*intdato; //aquie hago la operacion.

    pero no se como convertir la variable intresultado en una variable de tipo String y mostrarla en otro textField(1).

    31 de octubre, 2009 a las 6:35 pm
  12. Pat

    Querido José,

    Gracias por el ejemplo que presentas; es muy claro e ilustra perfectamente la problemática descrita.

    Sin embargo, no estoy de acuerdo con la semántica que has utilizado. En tu artículo, dices:

    “(…) en Java las variables, ya sean simples u objetos, se pasan siempre por valor.”

    A mi parecer, esta frase puede llevar a error. En mi opinión, en los parámetros a funciones en Java:

    “Los objetos se pasan por referencia” -> Es decir, el objeto se pasa al método utilizando una referencia a él.

    “La referencia a un objeto se pasa por valor” -> Es decir, se realiza una copia de la referencia al objeto.

    Un saludo

    26 de diciembre, 2009 a las 6:14 pm
  13. Jav

    Solucion al problema de paso por referencia de tipos primitivos: C#.

    Jajaja

    15 de septiembre, 2010 a las 11:26 pm