ArrayList que modifica el valor devuelto por el método "get"

Tengo por debajo de dos situaciones relacionadas con el método ArrayList get , una con la clase personalizada y otra con la clase String:

1. A continuación se muestra el ejemplo de la modificación de la clase Custom ArrayList elemento:

 ArrayList<MyClass> mTmpArray1 = new ArrayList<MyClass>(); MyClass myObj1 = new MyClass(10); mTmpArray1.add(myObj1); MyClass myObj2 = mTmpArray1.get(0); myObj2.myInt = 20; MyClass myObj3 = mTmpArray1.get(0); Log.d(TAG, "Int Value:"+myObj3.myInt); // Prints "20" 

2. A continuación se muestra el ejemplo de la modificación del elemento String ArrayList:

 ArrayList<String> mTmpArray2 = new ArrayList<String>(); mTmpArray2.add("Test_10"); String myStr1 = mTmpArray2.get(0); myStr1 = "Test_20"; String myStr2 = mTmpArray2.get(0); Log.d(TAG, "Str Value:"+myStr2); // Prints "Test_10" 

Así que en el caso de MyClass ArrayList, cuando llamo a get y modificar el valor, entonces veo el cambio está reflejando cuando vuelva a get .

Pero de la misma manera cuando modifico String ArrayList, entonces los cambios no están reflejando.

¿Cuál es la diferencia en el método get en ambos escenarios?
¿Es que en el caso de String, la clase String crea una copia profunda y devuelve un nuevo objeto, y en caso de que la clase personalizada se cree poco profunda?

En el primer escenario aplicable a "LinkedHashMap", "HashMap" y "List"?

No estás haciendo lo mismo en los dos casos.

Aquí se actualiza el estado de un objeto, por lo que el cambio afecta al objeto almacenado en la lista:

 myObj2.myInt = 20; 

Aquí se asigna un nuevo objeto a una variable local, por lo que la lista no se ve afectada:

 myStr1 = "Test_20"; 

Si String era mutable, podría haber modificado la String llamando a algún método, y el cambio se habría reflejado en el objeto almacenado en la lista:

 myStr1.setSomething(...); 

Por otro lado, si en el primer caso hubiera cambiado el valor de la variable local, el objeto almacenado en la lista no se habría visto afectado:

 myObj2 = new MyClass (...); 

Las cadenas son inmutables. No va a insertar la nueva cadena en la lista de matrices.

Cuando haces String myStr2 = mTmpArray2.get(0); , Incluso si estás apuntando a una referencia en ArrayList, cualquier intento de cambiar el valor, (debido a la inmutabilidad de String) creará una nueva String (myStr2) que no hará referencia a ArrayList.

Cuando haces myStr1 = "xxx" , en realidad no estás cambiando la referencia ArrayList, estás cambiando una nueva (copia) (ahora llamada myStr1) que fue agarrada de la ArrayList y tiene un ámbito local.

Lea más sobre Strings: Immutability of Strings en Java

Ahora, en el primer ejemplo, está señalando un objeto mutable (su clase personalizada) para que cambie literalmente el valor directo, a través de la referencia. Bienvenido a Java. 😉

Sin relación : Este código: MyClass myObj1 = new MyClass(10); Es (discutible) considerado malo. Es mejor usar un patrón de fábrica que es mucho más fácil de leer. En otras palabras, los constructores públicos con parámetros son difíciles de leer (por ejemplo, no tengo idea de lo que estoy construyendo cuando leo su código).

Un enfoque (quizás) mejor sería: MyClass myObj = MyClass.createInstanceWithCapacity(10); // i've invented the name because I don't know what your 10 is, but look at both, which one do you think is easier to understand upon first glance? MyClass myObj = MyClass.createInstanceWithCapacity(10); // i've invented the name because I don't know what your 10 is, but look at both, which one do you think is easier to understand upon first glance?

Descargo de responsabilidad : El comentario no relacionado anterior es mi opinión personal y no todos los desarrolladores estarán de acuerdo. 😉

Cuerdas tienen propiedad muy agradable llamado "Immutablity"

Esto significa que String no puede ser mutable (cambiado), cuando creamos / intentamos referirnos a la cadena antigua, se crea una nueva cadena de instancia. Y los cambios que hacemos se guardan en una nueva instancia y no afectan a la antigua cadena

Por ejemplo,

 String s = "Old String"; System.out.println("Old String : "+s); // output : Old String String s2 = s; s2 = s2.concat(" made New"); System.out.println("New String : "+s2); // output : Old String made New System.out.println("Old String is not changed : "+s); // output : Old String 

Éstas no son ninguna diferencia entre las dos llamadas "get". La diferencia está entre los tipos que el ArrayList mantiene, y lo que está haciendo las referencias que el método "get" devuelve.

En tu primer ejemplo, haz esto:

 MyClass myObj2 = mTmpArray1.get(0); myObj2.myInt = 20; 

Aquí, obtendrá una referencia a la instancia de MyClass en ArrayList en la posición 0 y está modificando un campo dentro de esta instancia.

En su segundo ejemplo, usted hace esto:

 String myStr1 = mTmpArray2.get(0); myStr1 = "Test_20"; 

Aquí, obtendrá una referencia a la instancia String en la lista de matrices y, a continuación, le dará a myStr1 una referencia a una cadena diferente que cree ("Test_20"). Es como si escribieras myObj2 = new MyClass(20); En la 2ª línea del primer ejemplo.

Por lo tanto, en resumen, en el primer ejemplo, se accede a un campo dentro del objeto mediante la alteración de la referencia que agarró. En el segundo ejemplo, simplemente cambió su referencia a punto en una cadena diferente.

También debo mencionar que en Java, cadenas son inmutables, es decir, una vez que han sido creados, no se puede cambiar.

String es una clase inmutable. Una línea como

 myStr1 = "Test_20"; 

No cambia el valor del objeto String al que myStr1 apunta. En su lugar, se crea una nueva String y myStr1 se modifica para apuntar a la nueva String. El String original no cambia y se puede recuperar de ArrayList.

Su objeto MyClass es claramente mutable. Sólo se crea una instancia y su estado se cambia por la asignación

 myObj2.myInt = 20; 

Por lo tanto, cuando este objeto se recupera de la ArrayList, su nuevo estado se ve.

Simplemente NO cambie la lista en su segundo ejemplo.

En el primer ejemplo, estás haciendo esto:

  1. Obtenga el primer objeto de la lista y guárdelo en la variable llamada 'myObj2'
  2. Modifique el objeto almacenado en la variable 'myObj2' estableciendo el valor int de este objeto

Pero su segundo ejemplo es completamente diferente:

 String myStr1 = mTmpArray2.get(0); myStr1 = "Test_20"; 

Permítanme traducir eso:

  1. Obtenga el primer elemento de la lista y guárdelo en la variable llamada 'myStr1'.
  2. Establezca el valor de la variable 'myStr1' en "Test_20"

Por lo tanto, en caso de que esté modificando una variable del objeto almacenado en la lista. En caso de que usted está recuperando el objeto almacenado en la lista – y luego reutilizar la variable que ha almacenado ese objeto recuperado y utilizarlo para algo nuevo – pero eso no cambia la lista original, por supuesto.

Para modificar su lista para un tipo como cadena, necesitaría usar set (x, "Test_20").

  • Se filtró un objeto SQLiteConnection para la base de datos. Por favor, corrija su aplicación
  • Java.lang.NoClassDefFoundError: com / android / utils / ILogger en Visual Studio 2015
  • N-Puzzle pseudo-aleatorio barajar?
  • ¿El zócalo del cliente androide, cómo leer datos?
  • Indicador de actualización de Android SwipeRefreshLayout no visible
  • ¿Por qué esta tarea de fondo falla con una excepción fatal?
  • ¿Hay grandes diferencias entre el objetivo-c y Java, o iPhone y Android?
  • Android Comprobación de si un tamaño de archivo ha excedido un determinado valor
  • Fecha de creación del archivo en android
  • El desplazamiento de la vista web de Android no funciona
  • Cómo obtener los elementos seleccionados de un elemento de opción múltiple en un Alert.Builder?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.