Arrays.asList (array)和 new ArrayList < Integer > (Arrays.asList (array))的区别

有什么区别

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

  • 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));
224962 次浏览
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);

这是因为由 Arrays.asList()产生的 ArrayList不属于 java.util.ArrayList类型。

Arrays.asList()创建一个类型为 java.util.Arrays$ArrayListArrayList,它不扩展 java.util.ArrayList,而只扩展 java.util.AbstractList

  1. 首先,让我们看看这是干什么的:

    Arrays.asList(ia)
    

    它接受一个数组 ia并创建一个实现 List<Integer>的包装器,这使得原始数组可以作为一个列表使用。不复制任何内容,只创建一个包装器对象。列表包装器上的操作将传播到原始数组。这意味着如果对列表包装器进行洗牌,原始数组也会被洗牌,如果覆盖一个元素,它就会在原始数组中被覆盖,等等。当然,有些 List操作不允许在包装器上执行,比如从列表中添加或删除元素,您只能读取或覆盖元素。

    注意,列表包装器并没有扩展 ArrayList-它是一种不同类型的对象。ArrayList有它们自己的内部数组,它们在其中存储元素,并且能够调整内部数组的大小等等。包装器没有自己的内部数组,它只是将操作传播给给它的数组。

  2. 另一方面,如果随后将新数组创建为

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

    然后创建新的 ArrayList,它是原始 ArrayList的完整独立副本。虽然在这里也使用 Arrays.asList创建包装器,但是它只在构造新的 ArrayList时使用,并且在构造之后进行垃圾回收。这个新 ArrayList的结构完全独立于原始数组。它包含相同的元素(原始数组和这个新的 ArrayList在内存中引用相同的整数) ,但是它创建了一个新的内部数组来保存引用。因此,当你洗牌,添加,删除元素等,原来的数组是不变的。

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

在第2行中,Arrays.asList(ia)返回在 Arrays中定义的内部类对象的 List引用,也称为 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 数组列表

第1行创建一个新的 ArrayList对象,将从第2行获得的元素复制到该对象中。因此您可以做任何您想做的事情,因为 java.util.ArrayList提供了所有这些方法。

差异摘要-

当不使用 新的创建列表时,操作符 Arrays.asList ()方法返回一个 包装纸,这意味着:

  1. 可以执行添加/更新操作。

  2. 在原始数组中所做的更改也会反映到 List 中,反之亦然。

注意,在 Java8中,上面的‘ ia’必须是 Integer []而不是 int []。Int 数组的 Arrays.asList ()返回包含单个元素的列表。当使用 OP 的代码片段时,编译器会捕捉到问题,但是一些方法(例如 Collections.shuffle ())将无声地失败,无法完成您所期望的任务。

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. Java.util. 数组

  • 这是一个实用程序类,其中包含一组静态方法,可以对给定的数组进行操作
  • AsList 就是这样一个静态方法,它接受输入数组并返回一个 数组数组列表对象,数组数组列表是一个静态嵌套类,它扩展了 AbstractList < E > ,而后者又实现了 List 接口。
  • 所以 Arrays.asList (inarray)返回输入数组周围的 List 包装器,但是这个包装器是 而不是 java.util.ArrayList,它引用同一个数组,所以向 List 包装的数组添加更多元素也会影响原始数组,而且我们不能改变长度。

2. Java.util.ArrayList

  • ArrayList 有很多重载的构造函数

     public ArrayList() - // Returns arraylist with default capacity 10
    
    
    public ArrayList(Collection<? extends E> c)
    
    
    public ArrayList(int initialCapacity)
    
  • 因此,当我们将 Arrays.asList 返回的对象,即 List (AbstractList)传递给上面的第二个构造函数时,它将创建一个新的动态数组(当我们添加的元素超过其容量时,这个数组的大小会增加,而且新元素不会影响原始数组)浅表复制原始数组(肤浅的复制品意味着它只复制引用,而不会创建一组与原始数组相同的对象)

Arrays.asList()

此方法返回它自己的 List 实现。它接受一个数组作为参数,并在其上构建方法和属性,因为它不从数组中复制任何数据,而是使用原始数组,这会在修改 Arrays.asList()方法返回的列表时导致对原始数组的更改。

另一方面,ArrayList(Arrays.asList());ArrayList类的一个构造函数,它接受一个列表作为参数,并返回一个与列表无关的 ArrayList,也就是说,在本例中,Arrays.asList()作为参数传递。

这就是为什么你会看到这些结果。

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

上面的语句在输入数组上添加了包装器。因此,像 拿开这样的方法将不适用于列表引用对象‘ namesList’。

如果您尝试在现有的 array/list 中添加一个元素,那么您将得到“ Exception in thread“ main”java.lang。不支持的操作异常”。

上述操作是只读或只视图的。
不能在列表对象中执行添加或删除操作。

但是

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 类,所以在这里我们不会得到任何 UnSupportdOperationException。 在数组列表对象中所做的更改(方法在数组列表中添加或删除元素)将不会反映到原始 列表对象中。

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

首先,Arrays 类是一个实用工具类,它包含许多对 Arrays 进行操作的实用工具方法(感谢 Arrays 类)。否则,我们将需要创建自己的方法来对 Array 对象进行操作)

AsList ()方法:

  1. asList方法是 Array类的实用方法之一,它是一个静态方法,因此我们可以通过它的类名(如 Arrays.asList(T...a))来调用这个方法
  2. 现在有个转折。请注意,此方法不创建新的 ArrayList对象。它只返回对现有 Array对象的 List 引用(因此现在在使用 asList方法之后,将创建对现有 Array对象的两个引用)
  3. 这就是原因。所有操作 List对象的方法,可以使用 List引用操作这个 Array 对象。喜欢 例如,Array的长度是固定的,因此显然不能使用这个 List引用(如 list.add(10)list.remove(10);)从 Array对象中添加或删除元素。否则它将抛出 Unsupport tedOperationException)。
  4. 使用列表引用所做的任何更改都将反映在现有的 Array对象中(当您使用列表引用对现有 Array 对象进行操作时)

在第一种情况下,您创建了一个新的 Arraylist对象(在第二种情况下,只创建了对现有 Array 对象的引用,而没有创建新的 ArrayList对象) ,因此现在有两个不同的对象。一个是 Array对象,另一个是 ArrayList对象,它们之间没有任何联系(所以一个对象的变化不会在另一个对象中反映/影响(也就是说,在情况2中,ArrayArraylist是两个不同的对象)

案例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 the 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 the existing Array object using the List reference - valid
list2.set(1,11);
ia[2]=12;     // Making changes in the existing Array object using the Array reference - valid
System.out.println("list2: " + list2);
System.out.println("Array: " + Arrays.toString(ia));

许多人已经回答了机械方面的细节问题,但值得注意的是: 这是 Java 的一个糟糕的设计选择。

Java 的 asList方法被记录为“返回 固定大小列表...”。如果您得到它的结果并调用(比方说) .add方法,它将抛出一个 UnsupportedOperationException。这是违反直觉的行为!如果一个方法说它返回一个 List,标准的期望是它返回一个支持接口 List的方法的对象。开发人员不必记住无数 util.List方法中的 哪个,因为它们创建的 List实际上并不支持所有 List方法。

如果他们将方法命名为 asImmutableList,那就说得通了。或者,如果他们只是让这个方法返回一个实际的 List(并复制支持数组) ,那么这将是有意义的。他们决定同时支持运行时性能的 还有短名称,代价是违反了 最小惊讶原则和避免 UnsupportedOperationException的良好面向对象实践。

(此外,设计师可能已经制作了一个 interface ImmutableList,以避免过多的 UnsupportedOperationException。)

针对一些关于自 Java8以来 AsList ()行为的问题的评论:

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