Різниця між Arrays.asList (масив) та новим ArrayList <Integer> (Arrays.asList (масив))


119

Яка різниця між

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

де ia масив цілих чисел.

Я дізнався, що деякі операції не допускаються list2 . чому це так? як це зберігається в пам'яті (посилання / копія)?

Коли я перетасовую списки, list1це не впливає на початковий масив, алеlist2 робить. Але все list2ще дещо заплутано.

Те, ArrayListяк можна перенести список, відрізняється від створення новогоArrayList

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

2
Я пропоную вам доглянути варіант Google Guava . Lists.newArrayList(ia)робить незалежну копію, як і перший варіант. Це просто більш загальне і краще подивитися.
qben

Відповіді:


228
  1. Спочатку давайте подивимося, що це робить:

    Arrays.asList(ia)

    Він займає масив iaі створює обгортку, яка реалізує List<Integer>, що робить оригінальний масив доступним у вигляді списку. Нічого не копіюється, і все, лише один об'єкт обгортки створюється. Операції на обгортці списку передаються на вихідний масив. Це означає , що якщо ви перетасувати список обгортку, вихідний масив перемішується , а також, якщо ви перезаписати елемент, він отримує перезаписані в вихідному масиві, і т.д. Звичайно, деякі Listоперації не допускаються на обгортці, наприклад , додавання або видаляючи елементи зі списку, ви можете лише читати або перезаписувати елементи.

    Зауважте, що обгортка списку не поширюється ArrayList- це різний вид об'єкта. ArrayLists мають власний внутрішній масив, в якому вони зберігають свої елементи і здатні змінювати розмір внутрішніх масивів тощо. Обгортка не має власного внутрішнього масиву, вона лише розповсюджує операції з заданим йому масивом.

  2. З іншого боку, якщо згодом ви створите новий масив як

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

    тоді ви створюєте нову ArrayList, яка є повною незалежною копією оригіналу. Хоча тут ви також створюєте обгортку Arrays.asList, використовуючи лише під час будівництва нового ArrayListі згодом збирається сміття. Структура цього нового ArrayListабсолютно не залежить від вихідного масиву. Він містить однакові елементи (і вихідний масив, і ця нова ArrayListпосилання, однакові цілі числа в пам'яті), але він створює новий, внутрішній масив, який містить посилання. Отже, коли ви перетасуєте його, додаєте, видаляєте елементи тощо, початковий масив не змінюється.


9
@Dineshkumar Обгортка - це модель дизайну, яка перетворює один інтерфейс для класу в інший інтерфейс. Дивіться статтю з візерунком для обгортки . | Куди вам потрібно впасти? Я б запропонував використовувати List<Integer>для змінних типів (або аргументів методу тощо). Це робить ваш код більш загальним, і ви можете легко перейти до іншої Listреалізації за необхідності, без необхідності перезаписувати багато коду.
Петро Пудлак

Це хороше пояснення. Розширюючи це питання, метод Arrays.asList () також займає вараги. Якщо я передаю конкретні значення, скажу, що я: Arrays.asList (1,3,5) двічі, чи поверне він той самий Список?
sbsatter

27

Добре це тому, що ArrayListрезультат Arrays.asList()не є таким java.util.ArrayList. Arrays.asList()створює ArrayListтип, java.util.Arrays$ArrayListякий не розширюється, java.util.ArrayListа лише розширюєтьсяjava.util.AbstractList


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

У цьому випадку list1є типу ArrayList.

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

Тут список повертається як Listперегляд, тобто він має лише методи, приєднані до цього інтерфейсу. Отже, чому деякі методи заборонено list2.

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

Тут ви створюєте нове ArrayList. Ви просто передаєте це значення в конструкторі. Це не приклад кастингу. На кастингу це може виглядати приблизно так:

ArrayList list1 = (ArrayList)Arrays.asList(ia);

4

Я тут досить пізно, у будь-якому випадку відчуваю, що пояснення з посиланнями на документи краще буде тому, хто шукає відповіді.

  1. java.util.Arrays
  • Це клас утиліти з купою статичних методів для роботи з заданим масивом
  • asList - це такий статичний метод, який приймає масив введення і повертає об'єкт java.util.Arrays.ArrayList, який є статичним вкладеним класом, який розширює AbstractList, який inturn реалізує інтерфейс List.
  • Отже, Arrays.asList (inarray) повертає обгортку списку навколо вхідного масиву, але ця обгортка - java.util.Arrays.ArrayList, а не java.util.ArrayList, і вона посилається на той самий масив, тому додавання більше елементів до списку загорнутого масиву вплине на оригінальний теж, і також ми не можемо змінити довжину.
  1. java.util.ArrayList
  • ArrayList має купу перевантажених конструкторів

    public ArrayList () - // повертає arraylist з місткістю 10 за замовчуванням

    public ArrayList (колекція c)

    загальнодоступний ArrayList (int InitiCapacity)

  • Отже, коли ми передамо повернений Arrays.asList об'єкт, тобто List (AbstractList), другому конструктору вище, він створить новий динамічний масив (цей розмір масиву збільшується, оскільки ми додаємо більше елементів, ніж його ємність, а також нові елементи не впливатимуть на початковий масив ) дрібне копіювання оригінального масиву ( дрібна копія означає, що він копіює лише посилання та не створює новий набір тих самих об'єктів, що і в оригінальному масиві)


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

або

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

Вгорі Statement додає обгортку на вхідний масив. Тож такі методи, як додавання та видалення, не будуть застосовані до списку посилальних об’єктів 'namesList'.

Якщо ви спробуєте додати елемент у існуючий масив / список, то ви отримаєте "Виняток у потоці" main "java.lang.UnsupportedOperationException".

Вищеописана операція читається тільки або лише в режимі перегляду.
Ми не можемо виконувати операцію додавання або видалення в об'єкті списку. Але

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

або

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

У наведеному вище викладі ви створили конкретний екземпляр класу ArrayList і передали список як параметр.

У цьому випадку метод додавання та видалення буде працювати належним чином, оскільки обидва методи є з класу ArrayList, тому тут ми не отримаємо будь-якого UnSupportedOperationException.
Зміни, внесені в об’єкт Arraylist (метод додавання або видалення елемента в / з масиву), не відображатимуться в оригінальному об'єкті java.util.List.

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

3

Перш за все клас Arrays - це корисний клас, який не містить. корисних методів для роботи з масивами (завдяки класу Arrays інакше нам знадобилося б створити власні методи для дії на об’єктах Array)

метод asList ():

  1. asListметод є одним із корисних методів Arrayкласу, саме статичний метод, тому ми можемо назвати цей метод за назвою його класу (наприклад Arrays.asList(T...a))
  2. Тепер ось поворот, зауважте, що цей метод не створює новий ArrayListоб’єкт, він просто повертає посилання списку на існуючий Arrayоб’єкт (тому тепер після використання asListметоду Arrayстворюються дві посилання на існуючий об’єкт)
  3. і це причина, що всі методи, які працюють на Listоб'єкті, НЕ можуть працювати на цьому об’єкті масиву, використовуючи Listпосилання, наприклад, наприклад, Arrayрозмір s фіксується по довжині, отже, ви, очевидно, не можете додавати або видаляти елементи з Arrayоб'єкта за допомогою цього Listпосилання (наприклад, list.add(10)або list.remove(10);інакше це кине UnsupportedOperationException)
  4. будь-яка зміна, яку ви робите за допомогою посилання на список, відображатиметься при виході Arrayз об'єкта (коли ви працюєте над існуючим об’єктом масиву за допомогою посилання списку)

У першому випадку ви створюєте новий Arraylistоб’єкт (у другому випадку створюється лише посилання на існуючий об’єкт Array, але не новий ArrayListоб’єкт), тому зараз є два різних об'єкти: один є Arrayоб'єктом, а інший - ArrayListоб'єктом і між ними немає зв'язку (так змінюється в одному об'єкті не відображатиметься / не впливає на інший об’єкт (тобто у випадку 2 Arrayі Arraylistє двома різними об'єктами)

випадок 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));

випадок 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));

3

Багато людей вже відповіли на механічні деталі, але варто зауважити: Java - це поганий вибір дизайну.

asListМетод Java задокументований як "Повертає список фіксованого розміру ...". Якщо ви візьмете його результат і зателефонуєте (скажіть) .addметодом, він кине an UnsupportedOperationException. Це неінтуїтивна поведінка! Якщо метод каже, що він повертає a List, стандартне очікування полягає в тому, що він повертає об'єкт, який підтримує методи інтерфейсу List. Розробнику не слід запам'ятовувати, який з незмінних util.Listметодів створює Lists, які насправді не підтримують усі Listметоди.

Якби вони назвали метод asImmutableList, це мало б сенс. Або якби вони просто мали метод повернути фактичне List(і скопіювати резервний масив), це мало б сенс. Вони вирішили прихилитись як до виконання, так і до коротких імен, за рахунок порушення як Принципу найменшого сюрпризу, так і доброї практики OO уникати UnsupportedOperationExceptions.

(Також дизайнери, можливо, зробили це interface ImmutableList, щоб уникнути безлічі UnsupportedOperationExceptionс.)


2

Зауважте, що в Java 8 "ia" вище має бути Integer [], а не int []. Arrays.asList () масиву int повертає список з одним елементом. Використовуючи фрагмент коду OP, компілятор вирішить проблему, але деякі методи (наприклад, Collections.shuffle ()) мовчки не зможуть виконати те, що ви очікуєте.


1
Я зіткнувся з проблемою компілятора, коли я зробив ArrayList <Integer> al = новий ArrayList <Integer> (Arrays.asList (a)); де a був int []. Мій аль отримав лише один елемент, який теж під час друку виглядав сміттям. Що це за елемент? І як це трапляється прийти туди? Я зіткнувся з цим питанням на Java 7
Jyotsana Nandwani

@JyotsanaNandwani Pls перевірити мою відповідь: stackoverflow.com/a/54105519/1163607
розмазня

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());
        }
    }
}

1

Arrays.asList()

цей метод повертає власну реалізацію List.It приймає масив як аргумент і будує способи та атрибути поверх нього, оскільки він не копіює жодних даних з масиву, але використовуючи оригінальний масив, це призводить до зміни в оригінальному масиві при зміні список, повернутий Arrays.asList() методом.

з іншої сторони.
ArrayList(Arrays.asList()); це конструктор ArrayListкласу, який бере аргумент списку і повертає той, ArrayListякий не залежить від списку, тобто. Arrays.asList()в цьому випадку передається як аргумент. саме тому ви бачите ці результати;


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

У другому рядку Arrays.asList(ia)повертає Listпосилання на об'єкт внутрішнього класу, визначений всередині Arrays, який також називається, ArrayListале є приватним і лише розширюється AbstractList. Це означає, що те, що повернулося, Arrays.asList(ia)є об’єктом класу, відмінним від того, від чого ви отримуєтеnew ArrayList<Integer> .

Ви не можете використовувати деякі операції для рядка 2, оскільки внутрішній приватний клас всередині Arrays не забезпечує ці методи.

Подивіться на це посилання і подивіться, що можна зробити з приватним внутрішнім класом: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/ Arrays.java # Arrays.ArrayList

Рядок 1 створює нові ArrayListоб'єкти, що копіюють елементи з того, що ви отримуєте з рядка 2. Отже, ви можете робити все, що завгодно, оскільки java.util.ArrayListнадає всі ці методи.


0

Підсумок різниці -

коли список створений без використання нового методу оператора Arrays.asList (), він повертає Wrapper, що означає

1. Ви можете виконати операцію додавання / оновлення.

2. зміни, внесені в оригінальний масив, будуть відображені і в List, і навпаки.


0

У відповідь на деякі коментарі, які задають питання про поведінку Arrays.asList () з часу 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);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.