132

和有什么区别

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

13 回答 13

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

    Arrays.asList(ia)
    

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

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

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

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

    然后创建 new ArrayList,它是原始副本的完整、独立副本。尽管在这里您也可以使用创建包装器Arrays.asList,但它仅在构建新包装器期间使用,ArrayList之后会被垃圾收集。这个新的结构ArrayList完全独立于原始数组。它包含相同的元素(原始数组和这个新数组都ArrayList引用内存中的相同整数),但它创建了一个新的内部数组来保存引用。因此,当您对其进行洗牌、添加、删除元素等操作时,原始数组是不变的。

于 2013-05-25T09:27:19.150 回答
30

嗯,这是因为ArrayList结果 fromArrays.asList()不是类型java.util.ArrayList

Arrays.asList()创建一个不扩展但仅扩展的ArrayListof 类型。java.util.Arrays$ArrayListjava.util.ArrayListjava.util.AbstractList

于 2013-05-25T09:13:13.140 回答
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);
于 2013-05-25T09:11:10.033 回答
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”。

如果您尝试在现有数组/列表中添加一个元素,那么您将得到“线程“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 类的具体实例并将一个列表作为参数传递。

在这种情况下,方法addremove将正常工作,因为这两个方法都来自 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
于 2018-04-25T11:08:52.533 回答
4

对于寻找答案的人来说,带有文档参考的解释会更好。

1. java.util.Arrays

  • 这是一个实用类,有一堆静态方法来操作给定的数组
  • asList是一种这样的静态方法,它接受输入数组并返回java.util.Arrays.ArrayList的对象,该对象是扩展 AbstractList<E> 的静态嵌套类,而 AbstractList<E> 又实现了 List 接口。
  • 所以 Arrays.asList(inarray) 返回一个围绕输入数组的 List 包装器,但是这个包装器是java.util.Arrays.ArrayList 而不是 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) 传递给上面的第二个构造函数时,它将创建一个新的动态数组(这个数组的大小会随着我们添加的元素超过其容量而增加,并且新元素不会影响原始数组)浅拷贝原始数组(浅拷贝意味着它只复制引用并且不会创建一组与原始数组相同的新对象)

于 2018-01-06T12:29:05.427 回答
4

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

asList() 方法:

  1. asList方法是Array类的实用方法之一,它是一个静态方法,这就是为什么我们可以通过它的类名来调用这个方法(比如Arrays.asList(T...a)
  2. 现在这里是转折点。请注意,此方法不会创建新ArrayList对象。它只是返回一个对现有Array对象的 List 引用(所以现在在使用方法之后,创建了对现有对象的asList两个引用)Array
  3. 这就是原因。对对象进行操作的所有方法List可能无法使用List引用在此 Array 对象上工作。例如,Arrays 大小的长度是固定的,因此您显然不能Array使用此引用从对象中添加或删除元素List(如list.add(10)list.remove(10);。否则它将抛出 UnsupportedOperationException)。
  4. 您使用列表引用所做的任何更改都将反映在现有Array的 s 对象中(因为您正在使用列表引用对现有 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));

案例二:

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));
于 2018-07-05T19:57:07.257 回答
2

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

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

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

(另外,设计者可能已经制作了interface ImmutableList, 以避免过多的UnsupportedOperationExceptions。)

于 2018-08-28T17:27:41.013 回答
2

请注意,在 Java 8 中,上面的 'ia' 必须是 Integer[] 而不是 int[]。int 数组的 Arrays.asList() 返回具有单个元素的列表。使用 OP 的代码片段时,编译器会发现问题,但某些方法(例如Collections.shuffle())会默默地无法执行您期望的操作。

于 2016-04-08T15:06:58.377 回答
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());
        }
    }
}
于 2016-08-25T11:21:28.090 回答
1

Arrays.asList()

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

另一方面,ArrayList(Arrays.asList()); 是一个ArrayList类的构造函数,它接受一个列表作为参数并返回一个ArrayList独立于列表的,即Arrays.asList()在这种情况下作为参数传递。

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

于 2018-02-24T05:53:28.650 回答
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);
于 2019-01-09T08:00:15.850 回答
0

差异摘要 -

当不使用new创建列表时,运算符 Arrays.asList() 方法返回一个包装器,这意味着:

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

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

于 2016-03-18T15:00:42.520 回答
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提供了所有这些方法。

于 2016-03-16T15:39:01.587 回答