Разница между Arrays.asList (массив) и новым ArrayList<Integer> (Arrays.asList (массив))
В чем разница между
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));
Ответы
Ответ 1
-
Во-первых, посмотрим, что это делает:
Arrays.asList(ia)
Он принимает массив ia
и создает оболочку, которая реализует List<Integer>
, что делает исходный массив доступным как список. Ничего не скопировано и все, создается только один объект-оболочка. Операции над оболочкой списка распространяются на исходный массив. Это означает, что если вы перетасовываете оболочку списка, исходный массив также перетасовывается, если вы перезаписываете элемент, он перезаписывается в исходном массиве и т.д. Конечно, некоторые операции List
не допускаются в оболочку, например, добавление или удаление элементов из списка, вы можете только читать или перезаписывать элементы.
Обратите внимание, что оболочка списка не расширяет ArrayList
- это другой вид объекта. ArrayList
имеют свой собственный внутренний массив, в котором они хранят свои элементы и могут изменять размеры внутренних массивов и т.д. Обертка не имеет собственного внутреннего массива, она только передает операции массиву, предоставленному ему.
-
С другой стороны, если впоследствии вы создадите новый массив как
new ArrayList<Integer>(Arrays.asList(ia))
тогда вы создаете новый ArrayList
, который является полной, независимой копией исходного. Хотя здесь вы создаете обертку, используя Arrays.asList
, она используется только при построении нового ArrayList
и после этого собирается мусор. Структура этого нового ArrayList
полностью не зависит от исходного массива. Он содержит те же элементы (как исходный массив, так и этот новый ArrayList
ссылаются на те же целые числа в памяти), но он создает новый внутренний массив, содержащий ссылки. Поэтому, когда вы перетасовываете его, добавляете, удаляете элементы и т.д., Исходный массив не изменяется.
Ответ 2
Ну, это потому, что ArrayList
в результате Arrays.asList()
не относится к типу java.util.ArrayList
. Arrays.asList()
создает ArrayList
типа java.util.Arrays$ArrayList
, который не расширяет java.util.ArrayList
, а только расширяет java.util.AbstractList
Ответ 3
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
Я довольно поздно здесь, так или иначе чувствовал, что объяснение с ссылками на документы будет лучше для тех, кто ищет ответ.
- java.util.Arrays
- Это служебный класс с кучей статических методов для работы с данным массивом.
- asList является одним из таких статических методов, который принимает входной массив и возвращает объект java.util.Arrays.ArrayList, который является статическим вложенным классом, который расширяет AbstractList, в котором inturn реализует интерфейс List.
- Таким образом, Arrays.asList(inarray) возвращает обертку List вокруг входного массива, но эта обертка является java.util.Arrays.ArrayList, а не java.util.ArrayList и ссылается на тот же массив, поэтому добавление большего количества элементов в массив обернутых списков повлияет оригинал тоже, а также мы не можем изменить длину.
- java.util.ArrayList
-
ArrayList имеет кучу перегруженных конструкторов
public ArrayList() -//возвращает массив с объемом по умолчанию 10
публичный ArrayList (Коллекция c)
public ArrayList (int initialCapacity)
-
Поэтому, когда мы передаем возвращенный объект Arrays.asList, т.е. List (AbstractList), во второй конструктор, описанный выше, он создаст новый динамический массив (размер этого массива увеличивается, когда мы добавляем больше элементов, чем его емкость, а также новые элементы не влияют на массив оригиналов. мелкое копирование исходного массива (мелкое копирование означает, что оно копирует только ссылки и не создает новый набор тех же объектов, что и в оригинальном массиве)
Ответ 5
Обратите внимание, что в Java 8, 'ia' выше, должно быть Integer [], а не int []. Arrays.asList() массива int возвращает список с одним элементом. При использовании фрагмента кода OP компилятор поймает проблему, но некоторые методы (например, Collections.shuffle()) будут молча выполнять то, что вы ожидаете.
Ответ 6
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
Ответ 7
Прежде всего, класс Arrays - это служебный класс, который не содержит никаких. служебных методов для работы с массивами (благодаря классу Arrays, в противном случае нам бы потребовалось создать собственные методы для работы с объектами Array)
Метод asList():
- Метод
asList
является одним из служебных методов класса Array
, это статический метод, поэтому мы можем вызывать этот метод по имени класса (например, Arrays.asList(T...a)
) - Теперь вот поворот, обратите внимание, что этот метод не создает новый объект
ArrayList
, он просто возвращает ссылку List на существующий объект Array
(поэтому теперь после использования метода asList
две ссылки на существующий объект Array
) - и это причина того, что все методы, которые работают с объектом
List
, могут НЕ работать с этим объектом Array, используя ссылку на List
как, например, размер Array
фиксирован по длине, поэтому вы, очевидно, не можете добавлять или удалять элементы из объекта Array
используя этот List
ссылка (например, list.add(10)
или list.remove(10);
противном случае будет list.remove(10);
UnsupportedOperationException) - любое изменение, которое вы делаете, используя ссылку на список, будет отражено при выходе из объекта
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));
Ответ 8
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());
}
}
}
Ответ 9
Arrays.asList()
этот метод возвращает свою собственную реализацию List.It принимает массив в качестве аргумента и создает поверх него методы и атрибуты, поскольку он не копирует какие-либо данные из массива, а использует исходный массив, что вызывает изменение исходного массива при изменении список, возвращаемый методом Arrays.asList()
.
с другой стороны.
ArrayList(Arrays.asList());
является конструктором класса ArrayList
который принимает список в качестве аргумента и возвращает ArrayList
который не зависит от списка, т.е. Arrays.asList()
в этом случае передается в качестве аргумента. вот почему вы видите эти результаты;
Ответ 10
Многие уже ответили на механические детали, но стоит отметить: это плохой выбор дизайна на Java.
Java asList
метод задокументирован как "Возвращает список фиксированного размера...". Если вы берете его результат и вызываете (скажем) метод .add
, он .add
UnsupportedOperationException
. Это не интуитивное поведение! Если метод сообщает, что возвращает List
, стандартное ожидание состоит в том, что он возвращает объект, который поддерживает методы интерфейса List
. Разработчик не должен запоминать, какой из многочисленных методов util.List
создает List
который на самом деле не поддерживает все методы List
.
Если бы они назвали метод asImmutableList
, это имело бы смысл. Или, если бы у них был только метод, возвращающий фактический List
(и копирующий резервный массив), это имело бы смысл. Они решили отдать предпочтение как производительности во время выполнения, так и коротким именам, за счет нарушения как принципа наименьшего сюрприза, так и добросовестной практики избегания исключений UnsupportedOperationException
.
(Также разработчики могли бы создать interface ImmutableList
, чтобы избежать множества исключений UnsupportedOperationException
.)
Ответ 11
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
предоставляет все эти методы.
Ответ 12
Резюме разницы -
когда список создается без использования нового метода оператора Arrays.asList(), он возвращает Wrapper, что означает
1. вы можете выполнить операцию добавления/обновления.
2. изменения, сделанные в исходном массиве, будут отображаться также в List и наоборот.
Ответ 13
В ответ на некоторые комментарии задаю вопросы о поведении 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
[[email protected] for 1-dim int array,
[[[email protected] for 2-dim int array,
[[[email protected] 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 [[[email protected]], where [[email protected] is the array object.
*/
System.out.println(Arrays.asList(arr1));
/*
This prints [[email protected], 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);