Копія Java ArrayList


214

У мене ArrayList l1розмір 10. Я присвоюю l1новому типу посилання список l2. Буде l1і l2вказувати на один і той же ArrayListоб’єкт? Або призначена копія ArrayListоб'єкта l2?

Якщо я використовую l2посилання, якщо я оновлюю об'єкт списку, він також відображає зміни l1типу посилання.

Наприклад:

List<Integer> l1 = new ArrayList<Integer>();
for (int i = 1; i <= 10; i++) {
    l1.add(i);
}

List l2 = l1;
l2.clear();

Чи немає іншого способу призначити копію об'єкта списку новій довідковій змінній, окрім створення двох об'єктів списку та копіювання у колекціях від старих до нових?

Відповіді:


460

Так, призначення буде просто скопіювати значення з l1(який є посиланням) на l2. Вони обидва будуть посилатися на один і той же об’єкт.

Створити дрібну копію досить просто:

List<Integer> newList = new ArrayList<>(oldList);

(Як один із прикладів.)


1
Чи можна скопіювати лише частину масиву архітектури на новий арселіст, Ефективно. наприклад: копіюйте елементи між позицією 5 та 10 з одного масиву на інший новий архівіст. У моєму застосуванні діапазон був би набагато більшим.
Ешвін

1
@Ashwin: Ну це операція O (N), але так ... ви можете використати List.subListдля отримання "перегляду" на розділ початкового списку.
Джон Скіт

що робити, якщо списки масивів вкладені (ArrayList<ArrayList<Object>>)? це створило б рекурсивно копії всіх дитячих об'єктів ArrayList?
Кіт

3
@Cat: Ні ... Це лише неглибока копія.
Джон Скіт

1
@ShanikaEdiriweera: Ви могли б це зробити вільно із потоками, так. Але складною частиною є створення глибокої копії, яку більшість об’єктів не надасть. Якщо ви маєте на увазі конкретний випадок, пропоную вам задати нове запитання з деталями.
Джон Скіт

67

Спробуйте використовувати Collections.copy(destination, source);


14
Хочете пояснити, чому це може бути кращим new ArrayList<>(source);?
Олексій

6
@atc - це ще один спосіб зробити дрібну копію, замість нового ArrayList () використовується інший алгоритм і може використовуватися для будь-якої реалізації списку, а не лише для ArrayList, тобто все :)
Сергій Загрійчук

14
Цей метод дуже вводить в оману! Власне, це опис є. Там написано: "копіює елементи з одного списку джерел у пункт призначення", але вони не копіюються! На них посилається, тому буде лише 1 копія об'єктів, і якщо вони можуть бути зміненими, ви потрапили в біду
ACV

5
ніде в ява-апі глибоке клонування не робиться жодним класом колекцій
Вікаш

Ця відповідь не має великого сенсу. Collections.copyзовсім не є альтернативою new ArrayList<>(source). Що на Collections.copyнасправді робить припустити , що по destination.size()крайней мере , так само великий як source.size(), а потім скопіювати індекс-індекс-діапазону з використанням set(int,E)методу. Метод не додає нових елементів до пункту призначення. Зверніться до вихідного коду, якщо він недостатньо зрозумілий з Javadoc.
Radiodef

35

Так l1і l2вкаже на ту саму посилання, на той самий об’єкт.

Якщо ви хочете створити новий ArrayList на основі іншого ArrayList, зробіть це:

List<String> l1 = new ArrayList<String>();
l1.add("Hello");
l1.add("World");
List<String> l2 = new ArrayList<String>(l1); //A new arrayList.
l2.add("Everybody");

Результат буде l1все одно матиме 2 елементи та l2матиме 3 елементи.


Чи можете ви поясніть, будь ласка, різницю між List<String> l2 = new ArrayList<String>(l1)та List<String> l2 = l1?
MortalMan

@MortalMan різниця полягає в тому, що l2 = новий ArrayList <String> (l1) є абсолютно новим об'єктом, і зміна l2 не впливає на l1, тоді як в списку <String> l2 = l1 ви не створюєте новий об'єкт, а просто посилаєтесь на той самий об'єкта як l1, тож у цьому випадку виконуючи таку операцію, як l2.add ("Всі"), l1.size () та l2.size () повернеться 3, оскільки обидва посилаються на один і той же об'єкт.
Альфредо Озоріо

19

Ще один зручний спосіб копіювання значень з src ArrayList в dest Arraylist:

ArrayList<String> src = new ArrayList<String>();
src.add("test string1");
src.add("test string2");
ArrayList<String> dest= new ArrayList<String>();
dest.addAll(src);

Це фактичне копіювання значень, а не просто копіювання посилань.


10
Я не зовсім впевнений, що це точно. мій тест показує зворотне (все ще посилається на той самий об’єкт)
invertigo

це рішення спрацювало для мене під час використання ArrayList з ArrayAdapter
albanx

1
Ця відповідь неправильна. addAll () просто копіює посилання, як сказав інвертиго. Це не глибока копія.
jk7

Для ArrayList <String> ця відповідь прийнятна, тому що String є незмінним, але спробуйте це на прикладі ОП, ArraList <Integer>, і ви побачите, що це просто копіювання посилань.
jk7

Тільки не мій день я здогадуюсь. Виявляється, такі класи, як Integer і Long, також непорушні, тому відповідь Харшала працює для простих випадків, таких як ArrayList <Integer> і ArrayList <String>. Там, де вона не вдається, - це складні об'єкти, які незмінні.
jk7

8

Існує метод addAll (), який служить меті копіювання одного ArrayList до іншого.

Наприклад, у вас є два списки масивів: sourceList і targetList , використовуйте код нижче.

targetList.addAll (sourceList);


він також просто копіює посилання.
Вікаш

4

Java не передає об'єкти, вона передає посилання (покажчики) на об'єкти. Отже, так, l2 і l1 - два покажчики на один і той же об'єкт.

Ви повинні зробити явну копію, якщо вам потрібні два різні списки з однаковим вмістом.


3
Як зробити "явну копію"? Я думаю, ви говорите про глибоку копію?
Cin316

1

List.copyOf ➙ немодифікується список

Ти запитав:

Чи немає іншого способу призначити копію списку

Java 9 принесла List.ofметоди використання літералів для створення немодифікованого Listневідомого конкретного класу.

LocalDate today = LocalDate.now( ZoneId.of( "Africa/Tunis" ) ) ;
List< LocalDate > dates = List.of( 
    today.minusDays( 1 ) ,  // Yesterday
    today ,                 // Today
    today.plusDays( 1 )     // Tomorrow
);

Поряд з цим ми також отримали List.copyOf. Цей метод також повертає немодифікований Listневідомий конкретний клас.

List< String > colors = new ArrayList<>( 4 ) ;          // Creates a modifiable `List`. 
colors.add ( "AliceBlue" ) ;
colors.add ( "PapayaWhip" ) ;
colors.add ( "Chartreuse" ) ;
colors.add ( "DarkSlateGray" ) ;
List< String > masterColors = List.copyOf( colors ) ;   // Creates an unmodifiable `List`.

Під "немодифікується" ми маємо на увазі кількість елементів у списку, і референт об'єкта, що міститься у кожному слоті як елемент, фіксується. Ви не можете додавати, видаляти або замінювати елементи. Але об'єкт референт проводиться в кожному елементі може або не може бути мінливим .

colors.remove( 2 ) ;          // SUCCEEDS. 
masterColors.remove( 2 ) ;    // FAIL - ERROR.

Дивіться цей код, який працює на веб-сайті IdeOne.com .

дати.toString (): [2020-02-02, 2020-02-03, 2020-02-04]

color.toString (): [AliceBlue, PapayaWhip, DarkSlateGray]

masterColors.toString (): [AliceBlue, PapayaWhip, Chartreuse, DarkSlateGray]

Ви запитували про посилання на об'єкти. Як говорили інші, якщо ви створили один список і призначили його двом еталонним змінним (покажчикам), у вас все ще є лише один список. Обидва вказують на один і той же список. Якщо ви використовуєте будь-який вказівник для зміни списку, обидва вказівники згодом побачать зміни, оскільки в пам'яті є лише один список.

Тому потрібно зробити копію списку. Якщо ви хочете, щоб цю копію неможливо змінити, скористайтеся List.copyOfметодом, описаним у цій відповіді. У такому підході ви закінчуєте два окремі списки, у кожному з елементів, які містять посилання на однакові змістові об'єкти. Наприклад, у нашому прикладі вище, використовуючи Stringоб’єкти для представлення кольорів, кольорові об’єкти десь пливуть у пам’яті. Два списки містять покажчики на однакові кольорові об’єкти. Ось схема.

введіть тут опис зображення

Перший список colorsможе змінюватися. Це означає, що деякі елементи можна було видалити, як видно з коду вище, де ми видалили початковий 3-й елемент Chartreuse(індекс 2 = порядковий 3). І елементи можна додавати. І елементи можна змінити, щоб вказати на якусь іншу, Stringнаприклад, OliveDrabабо CornflowerBlue.

На противагу цьому, чотири елементи masterColorsфіксуються. Ніякого видалення, жодного додавання та заміни іншого кольору. Це Listреалізація неможливо змінити.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.