Java ArrayList kopyası


214

Ben ArrayList l110 boyutlu bir var. l1Yeni liste referans türüne atar l2. Will l1ve l2aynı gelin ArrayListnesne? Veya ArrayListnesnenin bir kopyası atanmış mı l2?

Başvuruyu kullanırken, l2liste nesnesini güncelleştirirsem, l1başvuru türündeki değişiklikleri de yansıtır .

Örneğin:

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

List l2 = l1;
l2.clear();

Bir liste nesnesinin bir kopyasını yeni bir başvuru değişkenine 2 liste nesnesi oluşturmak ve koleksiyonlardan eskiden yeniye kopyalamak dışında başka bir yolu yok mu?

Yanıtlar:


460

Evet, atama sadece kopyalar değeri arasında l1(a referans olan) l2. Her ikisi de aynı nesneyi ifade eder.

Sığ bir kopya oluşturmak oldukça kolaydır:

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

(Bir örnek olarak.)


1
Bir arraylistin sadece bir kısmını yeni bir arrayliste verimli bir şekilde kopyalamak mümkün mü? örneğin: 5 ve 10 pozisyonları arasındaki öğeleri bir dizilenden başka bir dizilişe kopyalayın. Uygulamamda menzil çok daha büyük olurdu.
Ashwin

1
@Ashwin: O bir O (N) işlemi, ama evet ... List.subListorijinal listenin bir bölümüne "görünüm" almak için kullanabilirsiniz .
Jon Skeet

dizi listeleri yuvalanmışsa ne olur (ArrayList<ArrayList<Object>>)? bu tüm çocuk ArrayList nesnelerinin özyinelemeli kopyalarını oluşturur mu?
Kedi

3
@Cat: Hayır ... Bu sadece sığ bir kopya.
Jon Skeet

1
@ShanikaEdiriweera: Akarsu ile akıcı bir şekilde yapabilirsin, evet. Ancak zor kısım, çoğu nesnenin sağlayamayacağı derin bir kopya oluşturuyor . Aklınızda belirli bir durum varsa, ayrıntıları içeren yeni bir soru sormanızı öneririm.
Jon Skeet

67

14
Bunun neden tercih edilebileceğini açıklamak ister misiniz new ArrayList<>(source);?
Alex

6
@atc sığ kopya yapmanın bir yoludur, yeni ArrayList () yerine başka bir algoritma kullanılır ve sadece bir ArrayList için değil, herhangi bir Liste uygulaması için kullanılabilir :)
Sergii Zagriichuk

14
Bu yöntem çok yanıltıcı! Aslında, açıklaması. "Bir kaynak listesindeki öğeleri hedefe kopyalar" diyor, ancak kopyalanmıyor! Onlara referansta bulunulur, böylece nesnelerin sadece 1 kopyası olur ve değiştirilebilirlerse sorun
yaşarsınız

5
hiçbir yerde java-api derin klonlama herhangi bir koleksiyon sınıfı tarafından yapılır
Vikash

Bu cevap çok mantıklı değil. Collections.copyhiç bir alternatif değil new ArrayList<>(source). Ne Collections.copyaslında yok farz olduğu destination.size()kadar büyük, en az olduğu source.size()ve daha sonra menzil endeksi bazında endeks kullanarak kopyalama set(int,E)yöntemi. Yöntem değildir eklemek hedefe yeni unsurlar. Javadoc'tan yeterince açık değilse kaynak koduna bakın.
Radiodef

35

Evet l1ve l2aynı referansı, aynı nesneyi gösterecektir.

Diğer ArrayList'i temel alan yeni bir ArrayList oluşturmak istiyorsanız bunu yaparsınız:

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

Sonuç l1yine 2 eleman l2olacak ve 3 unsur olacak.


Arasındaki farkı açıklayabilir misiniz List<String> l2 = new ArrayList<String>(l1)ve List<String> l2 = l1?
MortalMan

@MortalMan farkı şu ki, l2 = yeni ArrayList <String> (l1) tamamen yeni bir nesne ve l2'yi değiştirmek l1'i etkilemezken, <String> l2 = l1 Listesi yeni bir nesne oluşturmuyorsunuz, sadece aynı referansa başvuruyorsunuz. bu durumda l2.add ("Herkes"), l1.size () ve l2.size () gibi bir işlem yapmak her ikisi de aynı nesneye başvurduğu için 3 değerini döndürür.
Alfredo Osorio

19

Değerleri src ArrayList'ten dest Arraylist'e kopyalamanın başka bir uygun yolu şudur:

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

Bu, yalnızca referansın kopyalanması değil, değerlerin gerçek kopyalanmasıdır.


10
bunun doğru olduğundan emin değilim.
testim

Bu çözüm ArrayList'i ArrayAdapter ile kullanırken benim için çalıştı
albanx

1
Bu cevap yanlış. addAll () sadece referansları invertigo'nun dediği gibi kopyalar. Bu derin bir kopya değil.
jk7

Bir ArrayList <String> için bu cevap kabul edilebilir çünkü String değişmezdir, ancak OP'nin bir ArraList <Integer> örneğiyle deneyin ve bunun sadece referansları kopyaladığını göreceksiniz.
jk7

Sadece benim günüm değil sanırım. Tamsayı ve Uzun gibi sınıfların da değişmez olduğu anlaşılır, bu nedenle Harshal'ın cevabı ArrayList <Integer> ve ArrayList <String> gibi basit durumlar için işe yarar. Başarısız olduğu yer, değiştirilemeyen karmaşık nesneler içindir.
jk7

8

Bir ArrayList'in diğerine kopyalanması amacına hizmet edecek addAll () yöntemi vardır .

Örneğin, iki Dizi Listeniz var: sourceList ve targetList , aşağıdaki kodu kullanın.

targetList.addAll (SourceList);


sadece referansları kopyalar.
Vikash

4

Java nesneleri iletmez, nesnelere referanslar (işaretçiler) iletir. Evet, l2 ve l1 aynı nesnenin iki göstergesidir.

Aynı içeriğe sahip iki farklı listeye ihtiyacınız varsa açık bir kopya oluşturmanız gerekir.


3
"Açık bir kopyayı" nasıl yaparsınız? Sanırım derin bir kopyadan mı bahsediyorsun?
Cin316

1

List.copyOf ➙ değiştirilemez liste

Sen sordun:

Listenin bir kopyasını atamanın başka bir yolu yok mu

Java 9 , bilinmeyen bir somut sınıfın List.ofdeğiştirilememesi için değişmezleri kullanma yöntemlerini getirdi List.

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

Bununla birlikte biz de var List.copyOf . Bu yöntem de Listbilinmeyen bir beton sınıfı değiştirilemez .

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

“Değiştirilemez” ile listedeki öğelerin sayısını kastediyoruz ve her yuvada bir öğe olarak tutulan nesne başvurusu sabittir. Öğe ekleyemez, bırakamaz veya değiştiremezsiniz. Ancak, her öğede tutulan nesne başvurusu değiştirilebilir olabilir veya olmayabilir .

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

IdeOne.com'da canlı olarak çalışan bu koda bakın .

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

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

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

Nesne referanslarını sordunuz. Diğerlerinin de söylediği gibi, bir liste oluşturup iki referans değişkenine (işaretçiler) atarsanız, yine de yalnızca bir listeniz vardır. Her ikisi de aynı listeye işaret ediyor. Listeyi değiştirmek için iki işaretçiden birini kullanırsanız, bellekte yalnızca bir liste olduğu için her iki işaretçi de değişiklikleri görür.

Bu yüzden listenin bir kopyasını oluşturmanız gerekir. Bu kopyanın değiştirilemez olmasını istiyorsanız, bu Yanıtta açıklanan List.copyOfyöntemi kullanın . Bu yaklaşımda, her biri aynı içerik nesnelerine referans tutan öğelere sahip iki ayrı listeyle sonuçlanırsınız. Örneğin, yukarıdaki örneğimizde Stringrenkleri temsil etmek için nesnelerin kullanılmasıyla , renk nesneleri bellekte bir yerde yüzer. İki liste aynı renk nesnelerine işaretçiler tutar. İşte bir diyagram.

resim açıklamasını buraya girin

İlk liste colorsdeğiştirilebilir. Bu, bazı öğelerin yukarıdaki kodda görüldüğü gibi kaldırılabileceği anlamına gelir, burada orijinal 3. öğeyi kaldırdık Chartreuse(2 dizini = sıra 3). Ve elemanlar eklenebilir. Ve elemanlar veya Stringgibi başka bir şeye işaret edecek şekilde değiştirilebilir .OliveDrabCornflowerBlue

Bunun aksine, dört elementi masterColorssabittir. Çıkarma, ekleme ve başka bir renk değiştirme yok. Bu Listuygulama değiştirilemez.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.