Salinan Java ArrayList

214

Saya memiliki ArrayList l1ukuran 10. Saya menetapkan l1jenis referensi daftar baru l2. Akankah l1dan l2menunjuk ke ArrayListobjek yang sama ? Atau salinan ArrayListobjek yang ditugaskan l2?

Saat menggunakan l2referensi, jika saya memperbarui objek daftar, itu mencerminkan perubahan dalam l1tipe referensi juga.

Sebagai contoh:

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

List l2 = l1;
l2.clear();

Apakah tidak ada cara lain untuk menetapkan salinan objek daftar ke variabel referensi baru, selain membuat 2 objek daftar, dan melakukan salinan koleksi dari yang lama ke yang baru?

pengguna309281
sumber

Jawaban:

460

Ya, tugas hanya akan menyalin nilai dari l1(yang merupakan referensi) untuk l2. Keduanya akan merujuk ke objek yang sama.

Namun, membuat salinan yang dangkal cukup mudah:

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

(Sama seperti satu contoh.)

Jon Skeet
sumber
1
Apakah mungkin untuk menyalin hanya sebagian dari arraylist ke arraylist baru, secara efisien. untuk eg: salin elemen antara posisi 5 dan 10 dari satu daftar susunan ke daftar susunan baru lainnya. Dalam aplikasi saya jangkauannya akan jauh lebih besar.
Ashwin
1
@Ashwin: Ya, ini operasi O (N), tapi ya ... bisa Anda gunakan List.subListuntuk mendapatkan "tampilan" ke bagian daftar asli.
Jon Skeet
bagaimana jika daftar array bersarang (ArrayList<ArrayList<Object>>)? akankah ini secara rekursif membuat salinan semua objek anak ArrayList?
Kucing
3
@ Kucing: Tidak ... Ini hanya salinan dangkal.
Jon Skeet
1
@ShanikaEdiriweera: Anda bisa melakukannya dengan lancar dengan aliran, ya. Tetapi bagian yang sulit adalah membuat salinan yang dalam, yang tidak akan disediakan oleh sebagian besar objek. Jika Anda memiliki kasus tertentu, saya sarankan Anda mengajukan pertanyaan baru dengan detail.
Jon Skeet
67

Coba gunakan Collections.copy(destination, source);

Sergii Zagriichuk
sumber
14
Mau jelaskan mengapa ini lebih disukai new ArrayList<>(source);?
Alex
6
@atc itu satu lagi cara untuk melakukan penyalinan dangkal, daripada ArrayList baru () itu menggunakan algoritma lain dan dapat digunakan untuk implementasi Daftar, bukan hanya untuk ArrayList, itu saja :)
Sergii Zagriichuk
14
Metode ini sangat menyesatkan! Sebenarnya, deskripsinya adalah. Ia mengatakan: "menyalin elemen dari satu daftar sumber ke tujuan", tetapi mereka tidak disalin! Mereka direferensikan sehingga hanya akan ada 1 salinan dari objek dan jika mereka bisa berubah, Anda dalam kesulitan
ACV
5
kloning mendalam java-api tidak dilakukan oleh kelas koleksi mana pun
Vikash
Jawaban ini tidak masuk akal. Collections.copysama sekali bukan alternatif untuk new ArrayList<>(source). Apa yang Collections.copysebenarnya dilakukan adalah berasumsi bahwa destination.size()setidaknya sebesar source.size(), dan kemudian salin rentang indeks demi indeks menggunakan set(int,E)metode. Metode ini tidak menambahkan elemen baru ke tujuan. Rujuk ke kode sumber jika tidak cukup jelas dari Javadoc.
Radiodef
35

Ya l1dan l2akan menunjuk ke referensi yang sama, objek yang sama.

Jika Anda ingin membuat ArrayList baru berdasarkan ArrayList lain, Anda melakukan ini:

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");

Hasilnya akan l1tetap memiliki 2 elemen dan l2akan memiliki 3 elemen.

Alfredo Osorio
sumber
Bisakah Anda jelaskan perbedaan antara List<String> l2 = new ArrayList<String>(l1)dan List<String> l2 = l1?
MortalMan
@MortalMan perbedaannya adalah l2 = new ArrayList <String> (l1) adalah objek yang sama sekali baru dan memodifikasi l2 tidak mempengaruhi l1, sedangkan List <String> l2 = l1 Anda tidak membuat objek baru tetapi hanya mereferensikan objek yang sama objek sebagai l1, jadi dalam hal ini melakukan operasi seperti l2.add ("Everybody"), l1.size () dan l2.size () akan mengembalikan 3 karena keduanya mereferensikan objek yang sama.
Alfredo Osorio
19

Cara mudah lain untuk menyalin nilai dari src ArrayList ke dest Arraylist adalah sebagai berikut:

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

Ini adalah penyalinan nilai aktual dan bukan hanya penyalinan referensi.

Harshal Waghmare
sumber
10
Saya tidak sepenuhnya yakin ini akurat. tes saya menunjukkan yang sebaliknya (masih merujuk objek yang sama)
invertigo
solusi ini bekerja untuk saya ketika menggunakan ArrayList dengan ArrayAdapter
albanx
1
Jawaban ini salah. addAll () hanya menyalin referensi seperti kata invertigo. Ini bukan salinan yang mendalam.
jk7
Untuk ArrayList <String> jawaban ini dapat diterima karena String tidak dapat diubah, tetapi cobalah dengan contoh OP, sebuah ArraList <Integer>, dan Anda akan melihatnya hanya menyalin referensi.
jk7
Hanya bukan hari saya kurasa. Ternyata kelas-kelas seperti Integer dan Long juga tidak berubah, jadi jawaban Harshal bekerja untuk kasus-kasus sederhana seperti ArrayList <Integer> dan ArrayList <String>. Dimana gagal adalah untuk objek kompleks yang tidak dapat diubah.
jk7
8

Ada metode addAll () yang akan melayani tujuan menyalin Satu ArrayList ke yang lain.

Misalnya Anda memiliki dua Daftar Array: sourceList dan targetList , gunakan kode di bawah ini.

targetList.addAll (sourceList);

vaibhav agrawal
sumber
itu juga hanya menyalin referensi.
Vikash
4

Java tidak melewatkan objek, ia meneruskan referensi (pointer) ke objek. Jadi ya, l2 dan l1 adalah dua pointer ke objek yang sama.

Anda harus membuat salinan eksplisit jika Anda memerlukan dua daftar berbeda dengan konten yang sama.

JB Nizet
sumber
3
Bagaimana Anda membuat "salinan eksplisit"? Saya kira Anda sedang berbicara tentang salinan yang mendalam?
Cin316
1

List.copyOf ➙ daftar tidak dapat diverifikasi

Kamu bertanya:

Apakah tidak ada cara lain untuk menetapkan salinan daftar

Java 9 membawa List.ofmetode untuk menggunakan literal untuk membuat Listkelas konkret yang tidak dapat dimodifikasi .

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

Bersamaan dengan itu kami juga mendapat List.copyOf. Metode ini juga mengembalikan Listkelas konkrit yang tidak dapat dimodifikasi .

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`.

Yang dimaksud dengan "tidak dapat dimodifikasi" adalah jumlah elemen dalam daftar, dan referensi objek yang disimpan di setiap slot sebagai elemen, diperbaiki. Anda tidak dapat menambah, menjatuhkan, atau mengganti elemen. Tetapi referensi objek yang dipegang di setiap elemen bisa berubah atau tidak bisa berubah .

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

Lihat kode ini berjalan langsung di IdeOne.com .

Date.toString (): [2020-02-02, 2020-02-03, 2020-02-04]

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

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

Anda bertanya tentang referensi objek. Seperti yang dikatakan orang lain, jika Anda membuat satu daftar dan menetapkannya ke dua variabel referensi (pointer), Anda hanya memiliki satu daftar. Keduanya menunjuk ke daftar yang sama. Jika Anda menggunakan salah satu pointer untuk mengubah daftar, kedua pointer nantinya akan melihat perubahan, karena hanya ada satu daftar di memori.

Jadi, Anda perlu membuat salinan daftar. Jika Anda ingin salinan itu tidak dapat dimodifikasi, gunakan List.copyOfmetode seperti yang dibahas dalam Jawaban ini. Dalam pendekatan ini, Anda berakhir dengan dua daftar terpisah, masing-masing dengan elemen yang memegang referensi ke objek konten yang sama. Sebagai contoh, dalam contoh kami di atas menggunakan Stringobjek untuk mewakili warna, objek warna melayang-layang di memori di suatu tempat. Kedua daftar memegang pointer ke objek warna yang sama. Ini adalah diagram.

masukkan deskripsi gambar di sini

Daftar pertama colorsdapat dimodifikasi. Ini berarti bahwa beberapa elemen dapat dihapus seperti yang terlihat dalam kode di atas, di mana kami menghapus elemen ke-3 asli Chartreuse(indeks 2 = ordinal 3). Dan elemen dapat ditambahkan. Dan elemen-elemen dapat diubah untuk menunjuk ke yang lain Stringseperti OliveDrabatauCornflowerBlue .

Sebaliknya, keempat elemen tersebut masterColorsadalah tetap. Tidak menghapus, tidak menambahkan, dan tidak mengganti warna lain. Itu Listimplementasi unmodifiable.

Basil Bourque
sumber