Значение изменения ArrayList, возвращаемое методом «get»

У меня ниже двух ситуаций, связанных с методом getArrayList, с настраиваемым классом и с классом String:

1. Ниже приведен пример изменения элемента Custom ArrayList:

 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. Ниже приведен пример изменения элемента 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" 

Поэтому в случае MyClass ArrayList, когда я вызываю get и изменяю значение, я вижу, что изменение отражается, когда я снова get .

Но так же, когда я изменяю String ArrayList, изменения не отражаются.

В чем отличие метода get в обоих сценариях?
Является ли это тем, что в случае String класс String создает глубокую копию и возвращает новый объект, а в случае пользовательского класса создается мелкая копия?

В первом сценарии применимы к «LinkedHashMap», «HashMap» и «List»?

Вы не делаете то же самое в двух случаях.

Здесь вы обновляете состояние объекта, поэтому изменение влияет на объект, хранящийся в списке:

 myObj2.myInt = 20; 

Здесь вы назначаете новый объект локальной переменной, поэтому список не изменяется:

 myStr1 = "Test_20"; 

Если String был изменен, вы могли бы изменить String, вызвав некоторый метод, и это изменение было бы отражено в объекте, хранящемся в списке:

 myStr1.setSomething(...); 

С другой стороны, если в первом случае вы изменили значение локальной переменной, объект, хранящийся в списке, не был бы затронут:

 myObj2 = new MyClass (...); 

Строки неизменяемы. Вы не вставляете новую строку в список массивов.

Когда вы делаете String myStr2 = mTmpArray2.get(0); , Даже если вы укажете на ссылку в ArrayList, любая попытка изменить значение будет (из-за неизменности String) создать новую String (myStr2), которая больше не будет ссылаться на ArrayList.

Когда вы делаете myStr1 = "xxx" , вы фактически не изменяете ссылку ArrayList, вы меняете новую (копию) (теперь называемую myStr1), которая была схвачена из ArrayList и имеет локальную область.

Читайте еще несколько статей о строках: неизменность строк в Java

Теперь в первом примере вы указываете на изменяемый объект (ваш собственный класс), так что вы буквально меняете прямое значение через ссылку. Добро пожаловать на Java. 😉

Несвязанный : Этот код: MyClass myObj1 = new MyClass(10); (Возможно) считается плохим. Лучше использовать шаблон фабрики , который намного легче читать. Другими словами, публичные конструкторы с параметрами трудно читать (например, я не знаю, что я создаю, когда читаю ваш код).

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?

Отказ от ответственности : вышеупомянутый несвязанный комментарий – мое личное мнение, и не все разработчики согласятся. 😉

Строки имеют очень приятное свойство под названием «Immutablity»

Это означает, что String нельзя изменить (изменить), когда мы создаем / пытаемся ссылаться на старую строку, создается новая строка экземпляра. И любые изменения, которые мы делаем, сохраняются в новом экземпляре и не влияют на старую строку

Например,

 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 

Это не разница между двумя вызовами «получить». Разница между типами, которые хранится ArrayList, и тем, что вы делаете, возвращает метод get.

В первом примере вы выполните следующее:

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

Здесь вы получаете ссылку на экземпляр MyClass в ArrayList в позиции 0, и вы изменяете поле внутри этого экземпляра.

Во втором примере вы выполните следующее:

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

Здесь вы получаете ссылку на экземпляр String в списке массивов, а затем вы указываете myStr1 ссылку на другую строку, которую вы создаете («Test_20»). Это как если бы вы написали myObj2 = new MyClass(20); Во второй строке в первом примере.

Итак, короче говоря, в первом примере вы получаете доступ к полю внутри объекта, изменяя его из ссылки, которую вы захватили. Во втором примере вы просто изменили свою ссылку, указав на другую строку.

Я должен также упомянуть, что в Java строки являются неизменяемыми, что означает, что после их создания они не могут быть изменены.

Строка – непреложный класс. Линия, подобная

 myStr1 = "Test_20"; 

Не меняет значение объекта myStr1 который указывает myStr1 . Вместо этого создается новая String, а myStr1 изменен, чтобы указать на новую String. Исходная строка не изменяется и может быть извлечена из массива ArrayList.

Ваш объект MyClass явно изменен. Создается только один экземпляр и его состояние изменяется назначением

 myObj2.myInt = 20; 

Следовательно, когда этот объект извлекается из ArrayList, его новое состояние видно.

Вы просто НЕ меняете список во втором примере.

В первом примере вы делаете это:

  1. Получите первый объект из списка и сохраните его в переменной «myObj2»
  2. Измените объект, хранящийся в переменной 'myObj2', установив значение int этого объекта

Но ваш второй пример совершенно другой:

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

Позвольте мне перевести это:

  1. Получите первый элемент из списка и сохраните его в переменной «myStr1».
  2. Установите значение переменной 'myStr1' в значение "Test_20"

Итак, в случае, если вы изменяете переменную объекта, хранящегося в списке. В случае двух вы извлекаете объект, хранящийся в списке, – а затем повторно используйте переменную, которую вы сохранили, в которой был получен объект, и используете его для чего-то нового, но это, конечно, не изменяет исходный список.

Чтобы изменить список для типа типа string, вам нужно будет использовать set (x, «Test_20»).