¿Por qué se modifica un parámetro ArrayList, pero no un parámetro String? [duplicar]


Esta pregunta ya tiene una respuesta aquí:

public class StackOverFlow {
    public static void main(String[] args) {
        ArrayList<String> al = new ArrayList<String>();
        al.add("A");
        al.add("B");
        markAsNull(al);
        System.out.println("ArrayList elements are "+al);

        String str = "Hello";
        markStringAsNull(str);
        System.out.println("str "+ str);
    }
    private static void markAsNull(ArrayList<String> str){
        str.add("C");
        str= null;
    }
    private static void markStringAsNull(String str){
        str = str + "Append me";
        str = null;
    }
}

Esto produce:

ArrayList elements are [A, B, C]
str Hello

En el caso de ArrayList, los elementos añadidos están siendo recuperados. En el caso de String la llamada al método no tiene ningún efecto sobre la cadena que se pasa. ¿Qué está haciendo exactamente la JVM? ¿Puede alguien explicar en ¿destacamento?

Author: Gilles, 2013-04-08

5 answers

En el caso de los objetos string Arraylist, los elementos añadidos se recuperan. En el caso de String, la llamada al método no tiene ningún efecto sobre la Cadena que se pasa.

Sucede porque Java es Pass-by-Value y String s son inmutables

Cuando llamas

markAsNull(ArrayList<String> str)

Se crea una nueva referencia por nombre str para el mismo ArrayList señalado por al. Cuando add un elemento en str se agrega al mismo objeto. Más tarde se pone str a null pero el objeto tiene los nuevos valores añadidos y se señala con a1.

Cuando llamas

markStringAsNull(String str)
{
    str = str + "Append me";
    // ...
}

La línea str = str + "Append me"; crea un nuevo objeto String añadiendo la cadena dada y asignándola a str. pero de nuevo es solo una referencia a la cadena real que ahora apunta a la cadena recién creada. (debido a la inmutabilidad) y la cadena original no se cambia.

 21
Author: Azodious,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-08 05:33:00

Los métodos markXAsNull están configurando las referencias locales para que sean null. Esto no tiene ningún efecto sobre el valor real almacenado en esa ubicación. El método main todavía tiene sus propias referencias a los valores, y puede llamar a println usando esos.

También, al hacer la concatenación de cadenas, toString() se llama al Objeto, y es por eso que la ArrayList se muestra como una lista de sus valores entre paréntesis.

 5
Author: Whymarrh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-08 05:28:42

Java sigue el concepto de valor passby ( no hay paso por referencia en java ) . Así que cuando pasas una cadena a la función envía un "copia de referencia" a esa cadena a la función. Así que incluso si se establece la variable a null en la función, cuando vuelve a la persona que llama se refiere a su valor original solamente. Es por eso que la cadena original no tiene efecto.

En el caso de Arraylist, copy of reference se refiere a la Arraylist original (que también es la misma en el caso de string). Pero cuando agrega algo a ArrayList, se refiere al objeto original y para que pueda ver el efecto. (try in method arraylist=new ArrayList (), your original arraylist will remain as it is).

En el caso de cadena, cuando se hace

Str = str + "abc";

Java crea un nuevo objeto de cadena que tendrá referencia a la cadena "xyzabc" ( por ejemplo, str="xyz") y "xyz" será elegible para la recolección de basura. Pero como " xyz " sigue teniendo una variable que se refiere a ella ( cadena original) no se recogerá basura. Pero tan pronto como la llamada a la función se sobrepone "xyzabc" va para la recolección de basura.

El resumen de la discusión es que, siempre que una referencia se refiera al mismo objeto, puede realizar cambios en la función, pero cuando intenta cambiar la referencia ( str=str+"abc"), se refiere al nuevo objeto en el método para que su objeto original permanezca como está.

 2
Author: trapaank,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-08 05:40:36

Del Libro: SCJP-Sun Certified Programmer for Java 6 Study Guide (Katty Sierra - Bert Bates) Capítulo 3 Objetivo 7.3-Pasar Variables A Métodos

Java es en realidad pasar por valor para todas las variables que se ejecutan dentro de una sola VM. Pasar por valor significa pasar por valor variable. Y eso significa, pasar-por-copia-de- variable!

La línea de fondo en pasar por valor: el método llamado no puede cambiar el variable, aunque para las variables de referencia de objetos, el método llamado puede cambiar el objeto la variable a la que se hace referencia. Cuál es la diferencia entre cambiar la variable y cambiar el objeto? Para referencias de objetos, significa que el método llamado no puede reasignar la variable de referencia original de la persona que llama y hacer que se refiera a un objeto diferente, o null. Por ejemplo, en el siguiente fragmento de código,

void bar() {
Foo f = new Foo();
doStuff(f);
}
void doStuff(Foo g) {
g.setName("Boo");
g = new Foo();
}

Reasignar g no reasignar f! Al final del método bar (), dos objetos Foo se han creado, uno referenciado por la variable local f y uno referenciado por la variable local (argumento) g. Porque el método doStuff () tiene una copia de variable de referencia, tiene una forma de llegar al objeto Foo original, por ejemplo para llamar el método setName (). Pero, el método doStuff() no tiene una manera de llegar a la variable de referencia f. Así que doStuff () puede cambiar valores dentro del objeto a, pero doStuff () no puede cambiar el contenido real (patrón de bits) de f. words, doStuff() puede cambiar el estado del objeto al que f se refiere, pero no puede f se refieren a un objeto diferente!

 2
Author: Sikorski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-08 05:41:03

En Java, puede crear un objeto, y referenciado por varios punteros. Llamar a un método mutador en cualquier puntero modificará efectivamente el único objeto, por lo tanto actualizando todas las demás referencias.

Pero si llama instrucciones de asignación de variables en una referencia, solo ese puntero se cambiará, ya que no hace ningún trabajo del lado del objeto (esto es lo mejor que podría explicar...).

Pasar un objeto a un parámetro efectivamente copiará la referencia, resultando en un solo objeto, con dos punteros, uno global y otro local.

Un punto más, ya que String es inmutable, realmente obtendrás un nuevo objeto, que es distinto del original (por el hecho de que tienes que decir a = a + "a"), por eso no modificará la cadena original.

 1
Author: Mordechai,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-08 05:34:47