Arrays.asList(array)和新ArrayList <Integer>(Arrays.asList(array))之间的区别


118

之间有什么区别

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

where ia是整数数组。

我得知不允许进行某些操作list2。为什么会这样呢?它如何存储在内存中(引用/副本)?

当我随机list1排列列表时,不会影响原始数组,但list2会影响原始数组。但是仍然list2有些混乱。

如何ArrayList被upcasted到列表不同于创建新ArrayList

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

2
我建议您照看Google Guava的选项。Lists.newArrayList(ia)就像第一个选择一样,制作一个独立的副本。它只是更笼统,更好看。
qben 2014年

Answers:


228
  1. 首先,让我们看看它的作用:

    Arrays.asList(ia)

    它需要一个数组ia并创建一个实现的包装器,该包装器List<Integer>将原始数组作为列表提供。什么也不会复制,所有的都只会创建一个包装对象。列表包装器上的操作将传播到原始数组。这意味着,如果您对列表包装器进行混洗,那么原始数组也将被混洗,如果您覆盖了一个元素,则原始数组中的元素也将被覆盖,依此类推。当然,有些List依此类推包装器上不允许进行操作,例如添加或从列表中删除元素,则只能读取或覆盖元素。

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

  2. 另一方面,如果您随后创建了一个新数组,

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

    然后创建new ArrayList,它是原始副本的完整独立副本。尽管在这里也使用来创建包装器Arrays.asList,但它仅在构造新包装器时使用,并且ArrayList随后被垃圾回收。此新产品的结构ArrayList完全独立于原始阵列。它包含相同的元素(原始数组和此新ArrayList引用在内存中都使用相同的整数),但是它创建了一个新的内部数组,其中包含引用。因此,当您随机播放,添加,删除元素等时,原始数组不会更改。


9
@Dineshkumar包装器是一种设计模式,可以将类的一个接口转换为另一个接口。请参阅包装器模式文章。| 您需要在哪里上投?我建议使用List<Integer>您的变量类型(或方法参数等)。这使您的代码更加通用,您可以List根据需要轻松切换到另一个实现,而不必重写很多代码。
彼得·普德拉克(PetrPudlák),

这是一个很好的解释。扩展这个问题,Arrays.asList()方法还采用了varargs。如果我传递特定值,请说我这样做:Arrays.asList(1,3,5)两次,它将返回相同的List吗?
sbsatter

27

嗯,这是因为ArrayListfrom Arrays.asList()不是这种类型的java.util.ArrayListArrays.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));

在这里,您正在创建一个new ArrayList。您只是在构造函数中为其传递了一个值。这不是铸造的例子。在投放时,可能看起来像这样:

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

4

我在这里很晚了,无论如何,使用文档引用进行解释对于寻求答案的人来说会更好。

  1. java.util.Arrays
  • 这是一个实用程序类,带有一堆可在给定数组上运行的静态方法
  • asList是一种这样的静态方法,它接受输入数组并返回java.util.Arrays.ArrayList的对象是扩展AbstractList的静态嵌套类,而AbstractList进而实现了List接口。
  • 因此Arrays.asList(inarray)返回围绕输入数组的List包装器,但是此包装器是java.util.Arrays.ArrayList而不是java.util.ArrayList,它引用了同一数组,因此向List包装的数组添加更多元素会影响也很原始,我们也不能改变长度。
  1. java.util.ArrayList
  • ArrayList有很多重载的构造函数

    public ArrayList()-//返回默认容量为10的arraylist

    公共ArrayList(Collection c)

    公共ArrayList(int initialCapacity)

  • 因此,当我们将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);         

上面的语句在输入数组上添加包装器。因此,诸如添加和删除之类的方法将不适用于列表引用对象“ namesList”。

如果尝试在现有数组/列表中添加元素,则将获得“线程“主”中的异常” 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

3

首先,Arrays类是一个实用程序类,其中不包含任何类。可以在Arrays上运行的实用方法(感谢Arrays类,否则我们将需要创建自己的方法来对Array对象进行操作)

asList()方法:

  1. asList方法是Array类的实用方法之一,它是静态方法,因此我们可以通过其类名来调用此方法(例如Arrays.asList(T...a)
  2. 现在是问题了,请注意,此方法不会创建新ArrayList对象,它只会返回对现有Array对象的List引用(因此,在使用asListmethod之后,两个对现有对象的引用Array将创建对象的)
  3. 这也是原因,在操作的所有方法List的对象,可以使用此阵列对象上不起作用List像例如,参考Array尺寸S是固定的长度,因此你显然不能从添加或删除元素Array对象使用此List引用(像list.add(10)list.remove(10);否则会抛出UnsupportedOperationException)
  4. 您使用列表引用所做的任何更改都将反映在退出的Arrays对象中(因为您正在使用列表引用对现有Array对象进行操作)

在第一种情况下,您正在创建一个新Arraylist对象(在第二种情况下,仅创建了对现有Array对象的引用,但没有创建新ArrayList对象),所以现在有两个不同的对象,一个是Arrayobject,另一个是ArrayListobject,并且它们之间没有连接(因此,更改在一个物体中不会被另一物体反射/影响(在情况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 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是一个糟糕的设计选择。

Java的asList方法记录为“返回固定大小的列表...”。如果获取其结果并调用(说)该.add方法,则它将抛出一个UnsupportedOperationException。这是不直观的行为!如果某个方法说它返回a List,则标准期望是它返回一个支持interface方法的对象List。开发人员不应该记住的许许多多的util.List方法创建List实际上并不支持所有S List的方法。

如果他们命名了方法asImmutableList,那将是有道理的。或者,如果他们只是让该方法返回实际值List(并复制后备数组),那将是有道理的。他们决定同时支持运行时性能简称,但要同时违反最小惊喜原则和避免UnsupportedOperationExceptions 的良好OO做法。

(此外,设计人员可能制作了interface ImmutableList,以避免过多UnsupportedOperationException的。)


2

注意,在Java 8中,上面的'ia'必须是Integer []而不是int []。一个int数组的Arrays.asList()返回一个包含单个元素的列表。使用OP的代码段时,编译器将捕获该问题,但是某些方法(例如Collections.shuffle())将无提示地无法执行您期望的操作。


1
当我执行ArrayList <Integer> al = new ArrayList <Integer>(Arrays.asList(a))时,我遇到了此编译器问题。其中a是int []。我的人只有一个元素,当打印时看起来也很垃圾。那是什么元素?以及它是怎么发生的呢?我在Java 7中遇到了这个问题
Jyotsana Nandwani

@JyotsanaNandwani Pls检查我的答案: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());
        }
    }
}

1

Arrays.asList()

此方法返回其自己的List实现。它将数组作为参数并在其之上构建方法和属性,因为它不是从数组中复制任何数据,而是使用原始数组,因此在修改时会导致原始数组的更改由返回的清单 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);

在第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提供了所有这些方法,因此您可以做任何您想做的事情。


0

差异摘要-

创建列表而不使用新的运算符Arrays.asList()方法时,它返回Wrapper,这意味着

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

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


0

自Java 8起,回应一些评论,询问有关Arrays.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);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.