Siempre pensé que Java era pase por referencia Sin embargo, he visto un par de publicaciones en blogs (por ejemplo, este blog ) que afirman que no lo es. Creo que no entiendo la distinción que hacen.
¿Cuál es la explicación?
Siempre pensé que Java era pase por referencia Sin embargo, he visto un par de publicaciones en blogs (por ejemplo, este blog ) que afirman que no lo es. Creo que no entiendo la distinción que hacen.
¿Cuál es la explicación?
Java es siempre pass-by-value. Lo difícil puede ser entender que Java pasa objetos como referencias y esas referencias se pasan por valor.
Es así:
Dog aDog = new Dog("Max");
foo(aDog);
aDog.getName().equals("Max"); // true
public void foo(Dog d) {
d.getName().equals("Max"); // true
d = new Dog("Fifi");
d.getName().equals("Fifi"); // true
}
En este ejemplo aDog.getName()
seguirá devolviendo "Max"
. d
no se sobrescribe en la función ya que la referencia al objeto se pasa por valor.
Igualmente:
Dog aDog = new Dog("Max");
foo(aDog);
aDog.getName().equals("Fifi"); // true
public void foo(Dog d) {
d.getName().equals("Max"); // true
d.setName("Fifi");
}
Acabo de darme cuenta de que has hecho referencia a mi artículo ;)
La especificación de Java dice que todo en Java es pass-by-value. En Java no existe el "pase por referencia".
La clave para entender esto es que algo como
Dog myDog;
es no un Perro; en realidad es un puntero a un perro.
Lo que significa, es que cuando tienes
Dog myDog = new Dog("Rover");
foo(myDog);
esencialmente estás pasando el dirección de los creados Dog
al objeto foo
método.
(Digo esencialmente porque los punteros de Java no son direcciones directas, pero es más fácil pensar en ellos de esa manera)
Supongamos que el Dog
reside en la dirección de memoria 42. Esto significa que pasamos 42 al método.
si el Método se definiera como
public void foo(Dog someDog) {
someDog.setName("Max"); // AAA
someDog = new Dog("Fifi"); // BBB
someDog.setName("Rowlf"); // CCC
}
veamos lo que está sucediendo.
someDog
se fija en el valor 42someDog
se sigue al Dog
que señala (el Dog
objeto en la dirección 42)Dog
(el de la dirección 42) se le pide que cambie su nombre por el de MaxDog
se crea. Digamos que está en la dirección 74someDog
a 74Dog
que señala (el Dog
objeto en la dirección 74)Dog
(el de la dirección 74) se le pide que cambie su nombre por el de RowlfAhora pensemos en lo que ocurre fuera del método:
En myDog
¿cambio?
Ahí está la clave.
Teniendo en cuenta que myDog
es un puntero y no un verdadero Dog
la respuesta es NO. myDog
sigue teniendo el valor 42; sigue apuntando al original Dog
.
Es perfectamente válido seguir una dirección y cambiar lo que está al final de la misma; sin embargo, eso no cambia la variable.
Java funciona exactamente igual que C. Puedes asignar un puntero, pasar el puntero a un método, seguir el puntero en el método y cambiar los datos a los que apuntaba. Sin embargo, no puedes cambiar a dónde apunta ese puntero.
En C++, Ada, Pascal y otros lenguajes que soportan pass-by-reference, se puede cambiar la variable que se pasó.
Si Java tuviera una semántica de paso por referencia, el foo
que definimos anteriormente habría cambiado donde myDog
apuntaba cuando asignaba someDog
en la línea BBB.
Piensa que los parámetros de referencia son alias de la variable pasada. Cuando ese alias se asigna, también lo hace la variable que se pasó.
¿Ayuda eso? (Tendré que añadir esto como anexo a mi artículo...)
-- Scott
Java siempre pasa los argumentos por valor NO por referencia.
Permítanme explicar esto a través de un ejemplo :
public class Main{
public static void main(String[] args){
Foo f = new Foo("f");
changeReference(f); // It won't change the reference!
modifyReference(f); // It will modify the object that the reference variable "f" refers to!
}
public static void changeReference(Foo a){
Foo b = new Foo("b");
a = b;
}
public static void modifyReference(Foo c){
c.setAttribute("c");
}
}
Lo explicaré por pasos:
Declarar una referencia llamada f
de tipo Foo
y asignarlo a un nuevo objeto de tipo Foo
con un atributo "f"
.
Foo f = new Foo("f");
Del lado del método, una referencia de tipo Foo
con un nombre a
se declara y se asigna inicialmente a null
.
public static void changeReference(Foo a)
Al llamar al método changeReference
la referencia a
se asignará al objeto que se pasa como argumento.
changeReference(f);
Declarar una referencia llamada b
de tipo Foo
y asignarlo a un nuevo objeto de tipo Foo
con un atributo "b"
.
Foo b = new Foo("b");
a = b
es reasignar la referencia a
NO f
al objeto cuyo atributo es "b"
.
Como usted llama modifyReference(Foo c)
método, una referencia c
se crea y se asigna al objeto con el atributo "f"
.
c.setAttribute("c");
cambiará el atributo del objeto que referencia c
apunta a él, y es el mismo objeto que referencia f
lo señala.
Espero que ahora entiendas cómo funciona el paso de objetos como argumentos en Java :)
Esto le dará una idea de cómo funciona realmente Java, hasta el punto de que en su próxima discusión sobre el paso por referencia o el paso por valor en Java simplemente sonreirá :-)
Primer paso, por favor, borra de tu mente esa palabra que empieza por 'p' "_ _ _ _ _ _", especialmente si vienes de otros lenguajes de programación. Java y 'p' no pueden escribirse en el mismo libro, foro o incluso txt.
Segundo paso, recuerda que cuando pasas un objeto a un método estás pasando la referencia del objeto y no el objeto mismo.
Ahora piensa en lo que hace/es la referencia/variable de un objeto:
En lo siguiente (por favor, no intente compilar/ejecutar esto...):
1. Person person;
2. person = new Person("Tom");
3. changeName(person);
4.
5. //I didn't use Person person below as an argument to be nice
6. static void changeName(Person anotherReferenceToTheSamePersonObject) {
7. anotherReferenceToTheSamePersonObject.setName("Jerry");
8. }
¿Qué ocurre?
Una imagen vale más que mil palabras:
¡Tenga en cuenta que las flechas anotherReferenceToTheSamePersonObject se dirigen al objeto y no a la variable person!
Si no lo has entendido, confía en mí y recuerda que es mejor decir que Java es pass by value . Bueno, pasar por valor de referencia . Oh, bueno, aún mejor es pasar-por-copiar-el-valor-de-la-variable! ;)
Ahora siéntanse libres de odiarme pero noten que dado esto no hay diferencia entre pasar tipos de datos primitivos y Objetos al hablar de los argumentos del método.
¡Siempre se pasa una copia de los bits del valor de la referencia!
¡Java es pass-by-value porque dentro de un método puedes modificar el Objeto referenciado tanto como quieras pero por mucho que lo intentes nunca podrás modificar la variable pasada que seguirá referenciando (no p _ _ _ _ _ _ _) el mismo Objeto pase lo que pase!
La función changeName anterior nunca podrá modificar el contenido real (los valores de los bits) de la referencia pasada. En otras palabras, changeName no puede hacer que la persona se refiera a otro objeto.
Por supuesto, puedes acortarlo y decir simplemente que ¡Java es pass-by-value!
Java siempre pasa por valor, sin excepciones, siempre .
Entonces, ¿cómo es posible que alguien pueda confundirse con esto, y creer que Java es pass by reference, o pensar que tiene un ejemplo de Java actuando como pass by reference? El punto clave es que Java nunca proporciona acceso directo a los valores de los propios objetos , en cualquier circunstancias. El único acceso a los objetos es a través de un referencia a ese objeto. Como los objetos Java son siempre se accede a través de una referencia, en lugar de hacerlo directamente, es común hablar de campos y variables y los argumentos del método como ser objetos cuando pedantemente sólo son referencias a objetos . La confusión se debe a este cambio de nomenclatura (estrictamente hablando, incorrecto).
Así, al llamar a un método
int
, long
etc.), el valor de paso es el valor real de la primitiva (por ejemplo, 3).Así que si tienes doSomething(foo)
y public void doSomething(Foo foo) { .. }
los dos Foos han copiado referencias que apuntan a los mismos objetos.
Naturalmente, pasar por valor una referencia a un objeto es muy parecido (indistinguible en la práctica) a pasar un objeto por referencia.
Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.