Perbedaan antara Arrays.asList (array) dan new ArrayList <Integer> (Arrays.asList (array))

119

Apa perbedaan antara

1.List<Integer> list1 = new ArrayList<Integer>(Arrays.asList(ia));  //copy
2.List<Integer> list2 = Arrays.asList(ia);

dimana iaarray bilangan bulat.

Saya mengetahui bahwa beberapa operasi tidak diizinkan masuk list2. kenapa gitu? bagaimana cara menyimpannya dalam memori (referensi / salinan)?

Ketika saya mengocok daftar, list1tidak memengaruhi larik asli tetapi memengaruhi list2. Tapi tetap saja list2agak membingungkan.

Bagaimana ArrayListdisorot ke daftar berbeda dengan membuat yang baruArrayList

list1 differs from (1)
ArrayList<Integer> list1 = new ArrayList<Integer>(Arrays.asList(ia));
Dineshkumar
sumber
2
Saya sarankan Anda menjaga opsi Google Guava . Lists.newArrayList(ia)membuat salinan independen, seperti opsi pertama. Ini lebih umum dan lebih baik untuk dilihat.
qben

Jawaban:

228
  1. Pertama, mari kita lihat apa fungsinya:

    Arrays.asList(ia)

    Ini mengambil array iadan membuat pembungkus yang mengimplementasikan List<Integer>, yang membuat array asli tersedia sebagai daftar. Tidak ada yang disalin dan semuanya, hanya satu objek pembungkus yang dibuat. Operasi pada pembungkus daftar disebarkan ke larik asli. Ini berarti bahwa jika Anda mengocok list wrapper, array asli juga akan diacak, jika Anda menimpa elemen, elemen tersebut akan ditimpa dalam array asli, dll. Tentu saja, beberapa Listoperasi tidak diizinkan pada wrapper, seperti menambahkan atau menghapus elemen dari daftar, Anda hanya dapat membaca atau menimpa elemen.

    Perhatikan bahwa pembungkus daftar tidak diperpanjang ArrayList- ini adalah jenis objek yang berbeda. ArrayLists memiliki array internal sendiri, di mana mereka menyimpan elemen-elemennya, dan dapat mengubah ukuran array internal, dll. Wrapper tidak memiliki array internalnya sendiri, ia hanya menyebarkan operasi ke array yang diberikan padanya.

  2. Di sisi lain, jika Anda selanjutnya membuat array baru sebagai

    new ArrayList<Integer>(Arrays.asList(ia))

    kemudian Anda membuat yang baru ArrayList, yang merupakan salinan lengkap dan independen dari yang asli. Meskipun di sini Anda juga membuat pembungkus menggunakan Arrays.asList, itu hanya digunakan selama pembangunan yang baru ArrayListdan sampah dikumpulkan sesudahnya. Struktur baru ArrayListini sepenuhnya tidak bergantung pada larik aslinya. Ini berisi elemen yang sama (baik array asli dan ArrayListreferensi baru ini adalah bilangan bulat yang sama dalam memori), tetapi membuat array internal baru, yang menyimpan referensi. Jadi ketika Anda mengocoknya, menambah, menghapus elemen, dll., Larik asli tidak berubah.

Petr Pudlák
sumber
9
@Dineshkumar Wrapper adalah pola desain yang menerjemahkan satu antarmuka untuk kelas ke antarmuka lain. Lihat artikel pola pembungkus . | Di mana Anda perlu tersadar? Saya akan menyarankan untuk menggunakan List<Integer>jenis variabel Anda (atau argumen metode, dll.). Ini membuat kode Anda lebih umum dan Anda dapat dengan mudah beralih ke Listimplementasi lain sesuai kebutuhan, tanpa harus menulis ulang banyak kode.
Petr Pudlák
Itu penjelasan yang bagus. Memperluas pertanyaan ini, metode Arrays.asList () juga membutuhkan vararg. Jika saya memberikan nilai tertentu, katakan saya lakukan: Arrays.asList (1,3,5) dua kali, apakah akan mengembalikan List yang sama?
sbsatter
27

Nah ini karena yang ArrayListdihasilkan Arrays.asList()bukan dari jenisnya java.util.ArrayList. Arrays.asList()menciptakan ArrayListtipe java.util.Arrays$ArrayListyang tidak meluas java.util.ArrayListtetapi hanya meluasjava.util.AbstractList

Chris
sumber
9
List<Integer> list1 = new ArrayList<Integer>(Arrays.asList(ia));  //copy

Dalam hal ini, list1adalah tipe ArrayList.

List<Integer> list2 = Arrays.asList(ia);

Di sini, daftar dikembalikan sebagai Listtampilan, artinya hanya memiliki metode yang dilampirkan ke antarmuka itu. Oleh karena itu mengapa beberapa metode tidak diperbolehkan list2.

ArrayList<Integer> list1 = new ArrayList<Integer>(Arrays.asList(ia));

Di sini, Anda sedang membuat file ArrayList. Anda hanya memberikan nilai di konstruktor. Ini bukan contoh casting. Dalam casting, mungkin terlihat seperti ini:

ArrayList list1 = (ArrayList)Arrays.asList(ia);
Christopher
sumber
4

Saya lumayan telat disini, lagian merasa penjelasan dengan referensi doc akan lebih baik bagi yang mencari jawaban.

  1. java.util.Arrays
  • Ini adalah kelas utilitas dengan sekumpulan metode statis untuk beroperasi pada larik tertentu
  • asList adalah salah satu metode statis yang mengambil larik input dan mengembalikan objek java.util.Arrays.ArrayList yang merupakan kelas bersarang statis yang memperluas AbstractList yang kemudian mengimplementasikan antarmuka Daftar.
  • Jadi, Arrays.asList (inarray) mengembalikan pembungkus Daftar di sekitar larik masukan tetapi pembungkus ini adalah java.util.Arrays.ArrayList dan bukan java.util.ArrayList dan ini merujuk ke larik yang sama sehingga menambahkan lebih banyak elemen ke larik terbungkus Daftar akan memengaruhi orignal juga dan kita tidak bisa mengubah panjangnya.
  1. java.util.ArrayList
  • ArrayList memiliki banyak konstruktor yang kelebihan beban

    public ArrayList () - // mengembalikan arraylist dengan kapasitas default 10

    public ArrayList (Koleksi c)

    public ArrayList (int initialCapacity)

  • Jadi, ketika kita mengirimkan objek yang dikembalikan Arrays.asList yaitu List (AbstractList) ke konstruktor kedua di atas, itu akan membuat array dinamis baru (ukuran array ini bertambah saat kita menambahkan lebih banyak elemen daripada kapasitasnya dan juga elemen baru tidak akan memengaruhi array orignal ) menyalin dangkal array asli ( salinan dangkal berarti menyalin di atas referensi saja dan tidak membuat set baru dari objek yang sama seperti di orignal array)

Gautam Tadigoppula
sumber
4
String names[] = new String[]{"Avinash","Amol","John","Peter"};
java.util.List<String> namesList = Arrays.asList(names);

atau

String names[] = new String[]{"Avinash","Amol","John","Peter"};
java.util.List<String> temp = Arrays.asList(names);         

Pernyataan Di Atas menambahkan pembungkus pada larik input. Jadi metode seperti tambah & hapus tidak akan berlaku pada objek referensi daftar 'namesList'.

Jika Anda mencoba menambahkan elemen dalam larik / daftar yang ada, maka Anda akan mendapatkan "Exception in thread" main "java.lang.UnsupportedOperationException".

Operasi di atas hanya bisa dibaca atau dilihat.
Kita tidak dapat melakukan operasi tambah atau hapus pada objek daftar. Tapi

String names[] = new String[]{"Avinash","Amol","John","Peter"};
java.util.ArrayList<String> list1 = new ArrayList<>(Arrays.asList(names));

atau

String names[] = new String[]{"Avinash","Amol","John","Peter"};
java.util.List<String> listObject = Arrays.asList(names);
java.util.ArrayList<String> list1 = new ArrayList<>(listObject);

Dalam pernyataan di atas Anda telah membuat instance konkret dari kelas ArrayList dan mengirimkan daftar sebagai parameter.

Dalam kasus ini, metode add & remove akan berfungsi dengan baik karena kedua metode berasal dari kelas ArrayList jadi di sini kita tidak akan mendapatkan UnSupportedOperationException.
Perubahan yang dibuat dalam objek Arraylist (metode menambah atau menghapus elemen di / dari daftar array) tidak akan tercermin dalam objek java.util.List asli.

String names[] = new String[] {
    "Avinash",
    "Amol",
    "John",
    "Peter"
};

java.util.List < String > listObject = Arrays.asList(names);
java.util.ArrayList < String > list1 = new ArrayList < > (listObject);
for (String string: list1) {
    System.out.print("   " + string);
}
list1.add("Alex"); //Added without any exception
list1.remove("Avinash"); //Added without any exception will not make any changes in original list in this case temp object.


for (String string: list1) {
    System.out.print("   " + string);
}
String existingNames[] = new String[] {
    "Avinash",
    "Amol",
    "John",
    "Peter"
};
java.util.List < String > namesList = Arrays.asList(names);
namesList.add("Bob"); // UnsupportedOperationException occur
namesList.remove("Avinash"); //UnsupportedOperationException
Avinash Pande
sumber
3

Pertama-tama kelas Array adalah kelas utilitas yang berisi no. metode utilitas untuk beroperasi pada Array (berkat kelas Array jika tidak kita perlu membuat metode kita sendiri untuk bertindak pada objek Array)

asList () metode:

  1. asListmetode adalah salah satu metode utilitas Arraykelas, itu adalah metode statis itulah sebabnya kita dapat memanggil metode ini dengan nama kelasnya (seperti Arrays.asList(T...a))
  2. Sekarang di sini adalah twistnya, harap dicatat bahwa metode ini tidak membuat ArrayListobjek baru , itu hanya mengembalikan referensi Daftar ke Arrayobjek yang ada (jadi sekarang setelah menggunakan asListmetode, dua referensi ke Arrayobjek yang ada dibuat)
  3. dan inilah alasannya, semua metode yang beroperasi pada Listobjek, TIDAK boleh bekerja pada objek Array ini menggunakan Listreferensi seperti misalnya, Arrayukuran s tetap panjangnya, maka Anda jelas tidak dapat menambah atau menghapus elemen dari Arrayobjek menggunakan Listreferensi ini (seperti list.add(10)atau list.remove(10);kalau tidak itu akan memunculkan UnsupportedOperationException)
  4. setiap perubahan yang Anda lakukan menggunakan referensi daftar akan tercermin dalam objek yang keluar Array(karena Anda beroperasi pada objek Array yang ada dengan menggunakan referensi daftar)

Dalam kasus pertama Anda membuat Arraylistobjek baru (dalam kasus ke-2 hanya referensi ke objek Array yang ada dibuat tetapi bukan ArrayListobjek baru ), jadi sekarang ada dua objek yang berbeda, satu adalah Arrayobjek dan yang lainnya adalah ArrayListobjek dan tidak ada koneksi di antara mereka (jadi perubahan dalam satu objek tidak akan dipantulkan / terpengaruh di objek lain (yaitu dalam kasus 2 Arraydan Arraylistmerupakan dua objek yang berbeda)

kasus 1:

Integer [] ia = {1,2,3,4};
System.out.println("Array : "+Arrays.toString(ia));
List<Integer> list1 = new ArrayList<Integer>(Arrays.asList(ia));  // new ArrayList object is created , no connection between existing Array Object
list1.add(5);
list1.add(6);
list1.remove(0);
list1.remove(0);
System.out.println("list1 : "+list1);
System.out.println("Array : "+Arrays.toString(ia));

kasus 2:

Integer [] ia = {1,2,3,4};
System.out.println("Array : "+Arrays.toString(ia));
List<Integer> list2 = Arrays.asList(ia); // creates only a (new ) List reference to existing Array object (and NOT a new ArrayList Object)
//  list2.add(5); //  it will throw java.lang.UnsupportedOperationException - invalid operation (as Array size is fixed)
list2.set(0,10);  // making changes in existing Array object using List reference - valid 
list2.set(1,11); 
ia[2]=12;     // making changes in existing Array object using Array reference - valid
System.out.println("list2 : "+list2);
System.out.println("Array : "+Arrays.toString(ia));
irfan
sumber
3

Banyak orang telah menjawab detail mekanisnya, tetapi perlu diperhatikan: Ini adalah pilihan desain yang buruk, oleh Java.

asListMetode Java didokumentasikan sebagai "Mengembalikan daftar ukuran tetap ...". Jika Anda mengambil hasilnya dan memanggil (katakan) .addmetode tersebut, ia akan melempar UnsupportedOperationException. Ini adalah perilaku yang tidak intuitif! Jika sebuah metode mengatakan ia mengembalikan a List, harapan standarnya adalah ia mengembalikan objek yang mendukung metode antarmuka List. Seorang pengembang tidak perlu mengingat mana dari sekian util.Listmetode yang dibuat Listyang tidak benar-benar mendukung semuaList metode.

Jika mereka telah menamai metodenya asImmutableList, itu masuk akal. Atau jika mereka hanya memiliki metode mengembalikan yang sebenarnya List(dan menyalin array pendukung), itu akan masuk akal. Mereka memutuskan untuk memilih kinerja runtime dan nama pendek, dengan mengorbankan Prinsip Kejutan Terkecil dan praktik baik-OO dalam menghindari UnsupportedOperationExceptions.

(Juga, perancang mungkin telah membuat interface ImmutableList, untuk menghindari sejumlah besar UnsupportedOperationExceptions.)

bukan hanya yeti
sumber
2

Perhatikan bahwa, di Java 8, 'ia' di atas harus berupa Integer [] dan bukan int []. Arrays.asList () dari larik int mengembalikan daftar dengan satu elemen. Saat menggunakan potongan kode OP, kompilator akan menangkap masalah, tetapi beberapa metode (misalnya Collections.shuffle ()) akan diam-diam gagal melakukan apa yang Anda harapkan.

Carl Burke
sumber
1
Saya menghadapi masalah compiler ini ketika saya melakukan ArrayList <Integer> al = new ArrayList <Integer> (Arrays.asList (a)); dimana a adalah int []. Al saya hanya mendapat satu elemen itu juga ketika dicetak tampak sampah. Elemen apa itu? Dan bagaimana itu bisa terjadi di sana? Saya menghadapi masalah ini di Jawa 7
Jyotsana Nandwani
@JyotsanaNandwani Tolong periksa jawaban saya: stackoverflow.com/a/54105519/1163607
NINCOMPOOP
1
package com.copy;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

public class CopyArray {

    public static void main(String[] args) {
        List<Integer> list1, list2 = null;
        Integer[] intarr = { 3, 4, 2, 1 };
        list1 = new ArrayList<Integer>(Arrays.asList(intarr));
        list1.add(30);
        list2 = Arrays.asList(intarr);
        // list2.add(40); Here, we can't modify the existing list,because it's a wrapper
        System.out.println("List1");
        Iterator<Integer> itr1 = list1.iterator();
        while (itr1.hasNext()) {
            System.out.println(itr1.next());
        }
        System.out.println("List2");
        Iterator<Integer> itr2 = list2.iterator();
        while (itr2.hasNext()) {
            System.out.println(itr2.next());
        }
    }
}
VicXj
sumber
1

Arrays.asList()

metode ini mengembalikan implementasinya sendiri dari List. Ini mengambil array sebagai argumen dan membangun metode dan atribut di atasnya, karena tidak menyalin data apa pun dari array tetapi menggunakan array asli, ini menyebabkan perubahan dalam array asli saat Anda memodifikasi daftar dikembalikan oleh Arrays.asList()metode.

di samping itu.
ArrayList(Arrays.asList()); adalah konstruktor ArrayListkelas yang mengambil list sebagai argumen dan mengembalikan ArrayListyang tidak bergantung pada list yaitu. Arrays.asList()dalam hal ini disahkan sebagai argumen. itulah mengapa Anda melihat hasil ini;

Kunal Singh Gusain
sumber
0
1.List<Integer> list1 = new ArrayList<Integer>(Arrays.asList(ia));  //copy
2.List<Integer> list2 = Arrays.asList(ia);

Di baris 2, Arrays.asList(ia)mengembalikan Listreferensi objek kelas dalam yang ditentukan di dalam Arrays, yang juga disebut ArrayListtetapi bersifat pribadi dan hanya diperluas AbstractList. Ini berarti apa yang dikembalikan dari Arrays.asList(ia)adalah objek kelas yang berbeda dari yang Anda dapatkan new ArrayList<Integer>.

Anda tidak dapat menggunakan beberapa operasi ke baris 2 karena kelas privat dalam Arraystidak menyediakan metode tersebut.

Lihatlah tautan ini dan lihat apa yang dapat Anda lakukan dengan kelas dalam privat: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/ Arrays.java # Arrays.ArrayList

Baris 1 membuat ArrayListobjek baru menyalin elemen dari apa yang Anda dapatkan dari baris 2. Jadi Anda dapat melakukan apa pun yang Anda inginkan karena java.util.ArrayListmenyediakan semua metode tersebut.

zek_w
sumber
0

Ringkasan perbedaan -

ketika daftar dibuat tanpa menggunakan metode operator baru Arrays.asList () itu mengembalikan Wrapper yang artinya

1. Anda dapat melakukan operasi tambah / perbarui.

2. perubahan yang dilakukan dalam larik asli juga akan direfleksikan ke Daftar dan sebaliknya.

Raj
sumber
0

Menanggapi beberapa komentar yang mengajukan pertanyaan tentang perilaku Arrays.asList () sejak Java 8:

    int[] arr1 = {1,2,3};
    /* 
       Arrays are objects in Java, internally int[] will be represented by 
       an Integer Array object which when printed on console shall output
       a pattern such as 
       [I@address for 1-dim int array,
       [[I@address for 2-dim int array, 
       [[F@address for 2-dim float array etc. 
   */
    System.out.println(Arrays.asList(arr1)); 

    /* 
       The line below results in Compile time error as Arrays.asList(int[] array)
       returns List<int[]>. The returned list contains only one element 
       and that is the int[] {1,2,3} 
    */
    // List<Integer> list1 = Arrays.asList(arr1);

    /* 
       Arrays.asList(arr1) is  Arrays$ArrayList object whose only element is int[] array
       so the line below prints [[I@...], where [I@... is the array object.
    */
    System.out.println(Arrays.asList(arr1)); 

    /* 
     This prints [I@..., the actual array object stored as single element 
     in the Arrays$ArrayList object. 
    */
    System.out.println(Arrays.asList(arr1).get(0));

    // prints the contents of array [1,2,3]
    System.out.println(Arrays.toString(Arrays.asList(arr1).get(0)));

    Integer[] arr2 = {1,2,3};
    /* 
     Arrays.asList(arr) is  Arrays$ArrayList object which is 
     a wrapper list object containing three elements 1,2,3.
     Technically, it is pointing to the original Integer[] array 
    */
    List<Integer> list2 = Arrays.asList(arr2);

    // prints the contents of list [1,2,3]
    System.out.println(list2);
ORANG BODOH
sumber