Arrays$ArrayList 的 Object 对象转换为 List<Object> 对象的技巧
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Arrays$ArrayList 的 Object 对象转换为 List<Object> 对象的技巧相关的知识,希望对你有一定的参考价值。
参考技术A 在一个开发案例中,需要把一个 Object 对象转换为 List<Object> 对象。这个 Object 对象本质上是 Arrays$ArrayList ,也就是 Arrays 类内部的 ArrayList 类。$ 是类与它的内部类之间的表示分隔符。Java 中可以通过 xxx.getClass().getName() 的方式得到一个对象所对应的类全名。
如果这个内部类是 public,那么我们可以通过点分法来进行显式转换,形如: (Arrays.ArrayList) xxx。可惜的是这个 ArrayList 类是 private,所以不能直接进行显式转换。
ArrayList 类提供了三种构造函数,其中的 ArrayList(Collection<? extends E> c) ,接受一个 Collection 作为入参,来初始化所创建的 ArrayList 对象:
按照这个思路,我们可以把这个 Object 先显式转换为 Collection,然后在传入 ArrayList 类。因为 Arrays$ArrayList 本身也实现了 Collection 类:
最终转换方法是: new ArrayList<>((Collection) params) 。
[Java中Arrays详解] https://www.cnblogs.com/wei-jing/p/10540192.html
[java.util.ArrayList与java.util.Arrays$ArrayList区别] https://www.cnblogs.com/yidaijiankuanzhongbuhui/p/9108148.html
Arrays.asList(array) 和 new ArrayList<Integer>(Arrays.asList(array)) 的区别
【中文标题】Arrays.asList(array) 和 new ArrayList<Integer>(Arrays.asList(array)) 的区别【英文标题】:Difference between Arrays.asList(array) and new ArrayList<Integer>(Arrays.asList(array)) 【发布时间】:2013-05-20 19:49:21 【问题描述】:有什么区别
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));
【问题讨论】:
我建议你照顾Google Guava's选项。Lists.newArrayList(ia)
制作独立副本,就像第一个选项一样。它只是更通用,更好看。
【参考方案1】:
首先,让我们看看这是做什么的:
Arrays.asList(ia)
它接受一个数组ia
并创建一个实现List<Integer>
的包装器,这使得原始数组可以作为一个列表使用。没有复制任何内容,只创建了一个包装器对象。列表包装器上的操作被传播到原始数组。这意味着如果你打乱列表包装器,原始数组也会被打乱,如果你覆盖一个元素,它会在原始数组中被覆盖,等等。当然,包装器上不允许一些List
操作,就像在列表中添加或删除元素一样,您只能读取或覆盖元素。
请注意,列表包装器不会扩展 ArrayList
- 它是一种不同的对象。 ArrayList
s 有自己的内部数组,它们在其中存储元素,并且能够调整内部数组的大小等。包装器没有自己的内部数组,它仅将操作传播到给定的数组。
另一方面,如果您随后创建一个新数组为
new ArrayList<Integer>(Arrays.asList(ia))
然后您创建新的ArrayList
,它是原始文件的完整、独立副本。尽管在这里您也使用Arrays.asList
创建了包装器,但它仅在构建新的ArrayList
期间使用,并且之后会被垃圾收集。这个新的ArrayList
的结构完全独立于原始数组。它包含相同的元素(原始数组和这个新的ArrayList
在内存中引用相同的整数),但它创建了一个新的内部数组来保存引用。所以当你打乱它,添加,删除元素等时,原来的数组是不变的。
【讨论】:
@Dineshkumar 包装器是一种将类的一个接口转换为另一个接口的设计模式。请参阅the wrapper pattern 文章。 |你需要在哪里上转?我建议将List<Integer>
用于您的变量类型(或方法参数等)。这使您的代码更加通用,您可以根据需要轻松切换到另一个 List
实现,而无需重写大量代码。
这是一个很好的解释。扩展这个问题,Arrays.asList() 方法也需要可变参数。如果我传递特定值,比如说我这样做: Arrays.asList(1,3,5) 两次,它会返回相同的列表吗?【参考方案2】:
嗯,这是因为Arrays.asList()
产生的ArrayList
不是java.util.ArrayList
的类型。
Arrays.asList()
创建了一个java.util.Arrays$ArrayList
类型的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】:对于寻求答案的人来说,带有文档参考的解释会更好。
1。 java.util.Arrays
这是一个实用类,其中包含用于对给定数组进行操作的一堆静态方法 asList 就是这样一种静态方法,它接受输入数组并返回 java.util.Arrays.ArrayList 的对象,该对象是扩展 AbstractList2。 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) 传递给上面的第二个构造函数时,它将创建一个新的动态数组(这个数组的大小会随着我们添加的元素超过其容量以及新的元素不会影响原始数组)浅拷贝原始数组(shallow copy 表示它仅复制引用,并且不会创建一组与原始数组相同的新对象)
【讨论】:
【参考方案5】: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
【讨论】:
【参考方案6】:首先,Arrays 类是一个实用类,它包含许多用于操作 Arrays 的实用方法(感谢 Arrays 类。否则,我们需要创建自己的方法来操作 Array 对象)
asList() 方法:
asList
方法是 Array
类的实用方法之一,它是一个静态方法,这就是为什么我们可以通过它的类名来调用这个方法(如 Arrays.asList(T...a)
)
现在是转折点。请注意,此方法不会创建新的 ArrayList
对象。它只是返回一个对现有Array
对象的列表引用(所以现在在使用asList
方法后,会创建对现有Array
对象的两个引用)
这就是原因。对 List
对象进行操作的所有方法可能不使用 List
引用在此 Array 对象上工作。喜欢
例如,Array
s 大小的长度是固定的,因此您显然不能使用此List
引用从Array
对象中添加或删除元素(如list.add(10)
或list.remove(10);
。否则它将抛出UnsupportedOperationException)。
您使用列表引用所做的任何更改都将反映在现有的 Array
s 对象中(因为您正在使用列表引用对现有 Array 对象进行操作)
在第一种情况下,您正在创建一个新的Arraylist
对象(在第二种情况下,只创建了对现有 Array 对象的引用,而不是新的ArrayList
对象),所以现在有两个不同的对象.一个是Array
对象,另一个是ArrayList
对象,它们之间没有任何联系(因此一个对象的更改不会反映/影响另一个对象(即,在情况2 中,Array
和Arraylist
是两个不同的对象)
案例一:
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));
【讨论】:
【参考方案7】:请注意,在 Java 8 中,上面的 'ia' 必须是 Integer[] 而不是 int[]。 int 数组的 Arrays.asList() 返回具有单个元素的列表。使用 OP 的代码 sn-p 时,编译器会发现问题,但某些方法(例如,Collections.shuffle())会默默地无法达到您的预期。
【讨论】:
我在执行 ArrayList很多人已经回答了机械细节,但值得注意的是: 对于 Java,这是一个糟糕的设计选择。
Java 的asList
方法记录为“返回一个固定大小 列表...”。如果你获取它的结果并调用(比如说).add
方法,它会抛出一个UnsupportedOperationException
。这是不直观的行为!如果一个方法说它返回一个List
,标准的期望是它返回一个支持接口List
的方法的对象。开发人员不必记住哪些在众多util.List
方法中创建了实际上并不支持所有List
方法的List
。
如果他们将方法命名为 asImmutableList
,那将是有意义的。或者,如果他们只是让该方法返回一个实际的 List
(并复制支持数组),那将是有意义的。他们决定同时支持运行时性能和短名称,代价是同时违反principle of least astonishment 和避免UnsupportedOperationException
s 的良好面向对象实践。
(另外,设计者可能会创建一个interface ImmutableList
,以避免过多的UnsupportedOperationException
s。)
【讨论】:
【参考方案9】: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());
【讨论】:
【参考方案10】:Arrays.asList()
此方法返回它自己的 List 实现。它将数组作为参数并在其上构建方法和属性,因为它不是从数组中复制任何数据,而是使用原始数组,当您修改 Arrays.asList()
方法返回的列表时,这会导致原始数组发生变化。
另一方面,ArrayList(Arrays.asList());
是ArrayList
类的构造函数,它接受一个列表作为参数并返回一个独立于列表的ArrayList
,即Arrays.asList()
在这种情况下作为参数传递。
这就是您看到这些结果的原因。
【讨论】:
【参考方案11】: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.ArrayList
第 1 行创建了一个新的 ArrayList
对象,该对象复制了从第 2 行获得的元素。因此您可以做任何您想做的事情,因为 java.util.ArrayList
提供了所有这些方法。
【讨论】:
【参考方案12】:针对一些 cmets 询问自 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);
【讨论】:
【参考方案13】:差异总结-
当不使用 new 创建列表时,运算符 Arrays.asList() 方法返回一个 wrapper,这意味着:
您可以执行添加/更新操作。
在原始数组中所做的更改也将反映到 List 中,反之亦然。
【讨论】:
以上是关于Arrays$ArrayList 的 Object 对象转换为 List<Object> 对象的技巧的主要内容,如果未能解决你的问题,请参考以下文章
转换 Arrays.asList 导致异常:java.util.Arrays$ArrayList 无法转换为 java.util.ArrayList
为啥 Arrays.asList() 返回自己的 ArrayList 实现