Разница между Arrays.asList (массив) и новым ArrayList <Integer> (Arrays.asList (массив))

83

В чем разница между

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) создает независимую копию, как и первый вариант. Это просто более общий и лучше смотреть.
Теги:
list
collections

13 ответов

171
Лучший ответ
  • Во-первых, посмотрим, что это делает:

    Arrays.asList(ia)
    

    Он принимает массив ia и создает оболочку, которая реализует List<Integer>, что делает исходный массив доступным как список. Ничего не скопировано и все, создается только один объект-оболочка. Операции над оболочкой списка распространяются на исходный массив. Это означает, что если вы перетасовываете оболочку списка, исходный массив также перетасовывается, если вы перезаписываете элемент, он перезаписывается в исходном массиве и т.д. Конечно, некоторые операции List не допускаются в оболочку, например, добавление или удаление элементов из списка, вы можете только читать или перезаписывать элементы.

    Обратите внимание, что оболочка списка не расширяет ArrayList - это другой вид объекта. ArrayList имеют свой собственный внутренний массив, в котором они хранят свои элементы и могут изменять размеры внутренних массивов и т.д. Обертка не имеет собственного внутреннего массива, она только передает операции массиву, предоставленному ему.

  • С другой стороны, если впоследствии вы создадите новый массив как

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

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

  • 8
    @Dineshkumar Оболочка - это шаблон проектирования, который переводит один интерфейс для класса в другой интерфейс. Смотрите статью об обёртке . | Куда тебе нужно прогнать? Я бы предложил использовать List<Integer> для типов переменных (или аргументов метода и т. Д.). Это делает ваш код более универсальным, и вы можете легко переключаться на другую реализацию List мере необходимости, без необходимости переписывать много кода.
19

Ну, это потому, что ArrayList в результате Arrays.asList() не относится к типу java.util.ArrayList. Arrays.asList() создает ArrayList типа java.util.Arrays$ArrayList, который не расширяет java.util.ArrayList, а только расширяет java.util.AbstractList

8
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);
3

Я довольно поздно здесь, так или иначе чувствовал, что объяснение с ссылками на документы будет лучше для тех, кто ищет ответ.

  1. java.util.Arrays
  • Это служебный класс с кучей статических методов для работы с данным массивом.
  • asList является одним из таких статических методов, который принимает входной массив и возвращает объект java.util.Arrays.ArrayList, который является статическим вложенным классом, который расширяет AbstractList, в котором inturn реализует интерфейс List.
  • Таким образом, Arrays.asList(inarray) возвращает обертку List вокруг входного массива, но эта обертка является java.util.Arrays.ArrayList, а не java.util.ArrayList и ссылается на тот же массив, поэтому добавление большего количества элементов в массив обернутых списков повлияет оригинал тоже, а также мы не можем изменить длину.
  1. java.util.ArrayList
  • ArrayList имеет кучу перегруженных конструкторов

    public ArrayList() -//возвращает массив с объемом по умолчанию 10

    публичный ArrayList (Коллекция c)

    public ArrayList (int initialCapacity)

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

2

Прежде всего, класс Arrays - это служебный класс, который не содержит никаких. служебных методов для работы с массивами (благодаря классу Arrays, в противном случае нам бы потребовалось создать собственные методы для работы с объектами Array)

Метод asList():

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

В первом случае вы создаете новый объект Arraylist (во 2-м случае создается только ссылка на существующий объект 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));
2
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);         

Выше оператора добавляет обертку на входной массив. Таким образом, такие методы, как add & remove, не будут применимы к объекту ссылки на список "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 и передали список в качестве параметра.

В этом случае метод add & remove будет работать должным образом, так как оба метода принадлежат классу ArrayList, поэтому здесь мы не получим никакого исключения UnSupportedOperationException.
Изменения, внесенные в объект Arraylist (метод добавления или удаления элемента в/из 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
2

Обратите внимание, что в Java 8, 'ia' выше, должно быть Integer [], а не int []. Arrays.asList() массива int возвращает список с одним элементом. При использовании фрагмента кода OP компилятор поймает проблему, но некоторые методы (например, Collections.shuffle()) будут молча выполнять то, что вы ожидаете.

  • 1
    Я столкнулся с этой проблемой компилятора, когда сделал ArrayList <Integer> al = new ArrayList <Integer> (Arrays.asList (a)); где был int []. Мой аль получил только один элемент, который тоже при печати выглядел мусором. Что это за элемент? И как это случилось, чтобы прийти туда? Я столкнулся с этой проблемой в Java 7
  • 0
    @JyotsanaNandwani Просьба проверить мой ответ: stackoverflow.com/a/54105519/1163607
1

Многие уже ответили на механические детали, но стоит отметить: это плохой выбор дизайна на Java.

Java asList метод задокументирован как "Возвращает список фиксированного размера...". Если вы берете его результат и вызываете (скажем) метод .add, он .add UnsupportedOperationException. Это не интуитивное поведение! Если метод сообщает, что возвращает List, стандартное ожидание состоит в том, что он возвращает объект, который поддерживает методы интерфейса List. Разработчик не должен запоминать, какой из многочисленных методов util.List создает List который на самом деле не поддерживает все методы List.

Если бы они назвали метод asImmutableList, это имело бы смысл. Или, если бы у них был только метод, возвращающий фактический List (и копирующий резервный массив), это имело бы смысл. Они решили отдать предпочтение как производительности во время выполнения, так и коротким именам, за счет нарушения как принципа наименьшего сюрприза, так и добросовестной практики избегания исключений UnsupportedOperationException.

(Также разработчики могли бы создать interface ImmutableList, чтобы избежать множества исключений UnsupportedOperationException.)

1

Arrays.asList()

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

с другой стороны.
ArrayList(Arrays.asList()); является конструктором класса ArrayList который принимает список в качестве аргумента и возвращает ArrayList который не зависит от списка, т.е. Arrays.asList() в этом случае передается в качестве аргумента. вот почему вы видите эти результаты;

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

Резюме разницы -

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

1. вы можете выполнить операцию добавления/обновления.

2. изменения, сделанные в исходном массиве, будут отображаться также в List   и наоборот.

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

В строке 2 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 предоставляет все эти методы.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню