Java中数组转集合总结
本文为joshua317原创文章,转载请注明:转载自joshua317博客 https://www.joshua317.com/article/243
一、使用Arrays.asList() 方法
package com.joshua317;
import java.util.*;
public class Main {
public static void main(String[] args) {
String[] namesArr = {"joshua317","joshua318","joshua319"};
List<String> namesLst = Arrays.asList(namesArr);
for (String name: namesLst) {
System.out.println(name);
}
}
}
2.该方法返回的List是长度是固定的(fixed),不是只读的。所以我们不能进行删除、添加操作,而可以使用set()方法进行修改元素操作。如果你对返回的List执行add()添加新元素,会返回UnsupportedOperationException。
package com.joshua317;
import java.util.*;
public class Main {
public static void main(String[] args) {
String[] namesArr = {"joshua317","joshua318","joshua319"};
List<String> namesLst = Arrays.asList(namesArr);
namesLst.add("joshua319");
for (String name: namesLst) {
System.out.println(name);
}
}
}
package com.joshua317;
import java.util.*;
public class Main {
public static void main(String[] args) {
String[] namesArr = {"joshua317","joshua318","joshua319"};
List<String> namesLst = Arrays.asList(namesArr);
namesLst.set(0,"joshua320");
System.out.println("==========list==========");
for (String name: namesLst) {
System.out.println(name);
}
System.out.println("==========array==========");
for (String name: namesArr) {
System.out.println(name);
}
}
}
注意:
1.如果我们想让转换为只读的List,可以使用Collections.unmodifiableList()方法来将数组转换为指定List。
package com.joshua317;
import java.util.*;
public class Main {
public static void main(String[] args) {
String[] namesArr = {"joshua317","joshua318","joshua319"};
final List<String> namesLst = Collections.unmodifiableList(Arrays.asList(namesArr));
for (String name: namesLst) {
System.out.println(name);
}
}
}
package com.joshua317;
import java.util.*;
public class Main {
public static void main(String[] args) {
String[] namesArr = {"joshua317","joshua318","joshua319"};
ArrayList<String> namesLst = new ArrayList<>(Arrays.asList(namesArr));
namesLst.add("joshua320");
for (String name: namesLst) {
System.out.println(name);
}
}
}
二、使用Collections.addAll()方法
使用Collections.addAll()方法没有第一种方法高效,但是更加灵活。同样也是新建一个ArrayList,将数组的内容复制进去。
package com.joshua317;
import java.util.*;
public class Main {
public static void main(String[] args) {
String[] namesArr = {"joshua317","joshua318","joshua319"};
ArrayList<String> namesLst = new ArrayList<>();
Collections.addAll(namesLst, namesArr);
namesLst.add("joshua320");
for (String name: namesLst) {
System.out.println(name);
}
}
}
1.没有Arrays.asList()快,但是更加灵活。
2.该方法实际上是将数组的内容复制到ArrayList中
3.因为是复制内容到ArrayList中,所以我们对ArrayList进行修改、添加、删除操作都不会影响原来的数组。
4.该方法相当于一个添加操作。该方法并不会覆盖ArrayList中已经存在的元素。
package com.joshua317;
import java.util.*;
public class Main {
public static void main(String[] args) {
String[] namesArr = {"joshua317","joshua318","joshua319"};
ArrayList<String> namesLst = new ArrayList<>();
Collections.addAll(namesLst, namesArr);
namesLst.add("---------");
Collections.addAll(namesLst, namesArr);
for (String name: namesLst) {
System.out.println(name);
}
}
}
三、使用ArrayList的构造方法
其实上面方法一中已经提到了,使用ArrayList的构造方法同时结合了Arrays.asList方法
package com.joshua317;
import java.util.*;
public class Main {
public static void main(String[] args) {
String[] namesArr = {"joshua317","joshua318","joshua319"};
ArrayList<String> namesLst = new ArrayList<>(Arrays.asList(namesArr));
namesLst.add("joshua320");
for (String name: namesLst) {
System.out.println(name);
}
}
}
ArrayList(Collection < ? extends E > c) : 构造一个包含特定容器的元素的列表,并且根据容器迭代器的顺序返回。 所以构造方法所做的事情如下:
1.将容器c转换为一个数组
2.将数组拷贝到ArrayList中称为”elementData”的数组中
ArrayList的构造方法的源码如下:
public ArrayList(Collection<? extends E> c) {
Object[] a = c.toArray();
if ((size = a.length) != 0) {
if (c.getClass() == ArrayList.class) {
elementData = a;
} else {
elementData = Arrays.copyOf(a, size, Object[].class);
}
} else {
// replace with empty array.
elementData = EMPTY_ELEMENTDATA;
}
}
四、使用ArrayList的addAll()方法
ArrayList的addAll()方法结合Arrays.asList方法使用
package com.joshua317;
import java.util.*;
public class Main {
public static void main(String[] args) {
String[] namesArr = {"joshua317","joshua318","joshua319"};
ArrayList<String> namesLst = new ArrayList<>();
namesLst.addAll(Arrays.asList(namesArr));
namesLst.add("joshua320");
for (String name: namesLst) {
System.out.println(name);
}
}
}
1.将容器c转换为一个数组
2.将数组拷贝到ArrayList中称为”elementData”的数组中
ArrayList的addAll方法的源码如下:
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}
五、拓展
5.1 为何对Arrays.asList()返回的List进行添加、删除操作会报错,而set方法却可以使用?
来看下Arrays.asList()方法相关源代码
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
private static class ArrayList<E> extends AbstractList<E>
implements RandomAccess, java.io.Serializable
{
private static final long serialVersionUID = -2764017481108945198L;
private final E[] a;
ArrayList(E[] array) {
a = Objects.requireNonNull(array);
}
@Override
public int size() {
return a.length;
}
@Override
public Object[] toArray() {
return a.clone();
}
@Override
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
int size = size();
if (a.length < size)
return Arrays.copyOf(this.a, size,
(Class<? extends T[]>) a.getClass());
System.arraycopy(this.a, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}
@Override
public E get(int index) {
return a[index];
}
@Override
public E set(int index, E element) {
E oldValue = a[index];
a[index] = element;
return oldValue;
}
@Override
public int indexOf(Object o) {
E[] a = this.a;
if (o == null) {
for (int i = 0; i < a.length; i++)
if (a[i] == null)
return i;
} else {
for (int i = 0; i < a.length; i++)
if (o.equals(a[i]))
return i;
}
return -1;
}
@Override
public boolean contains(Object o) {
return indexOf(o) != -1;
}
@Override
public Spliterator<E> spliterator() {
return Spliterators.spliterator(a, Spliterator.ORDERED);
}
@Override
public void forEach(Consumer<? super E> action) {
Objects.requireNonNull(action);
for (E e : a) {
action.accept(e);
}
}
@Override
public void replaceAll(UnaryOperator<E> operator) {
Objects.requireNonNull(operator);
E[] a = this.a;
for (int i = 0; i < a.length; i++) {
a[i] = operator.apply(a[i]);
}
}
@Override
public void sort(Comparator<? super E> c) {
Arrays.sort(a, c);
}
}
根据源码我们可以得知,Arrays.asList()方法返回的是个内部的ArrayList,这个类同样是AbstractList的一种实现。而该ArrayList就只有以下方法,并没有实现add和remove方法:
contain(Object)
get(int)
indexOf(Object)
set(int)
size()
toArray()
toArray(T[])
根本就没有add()和remove()方法。这个类由于是AbstractList的一种实现,AbstractList的add和remove方法会有异常抛出:
/**
* Appends the specified element to the end of this list (optional
* operation).
*
* <p>Lists that support this operation may place limitations on what
* elements may be added to this list. In particular, some
* lists will refuse to add null elements, and others will impose
* restrictions on the type of elements that may be added. List
* classes should clearly specify in their documentation any restrictions
* on what elements may be added.
*
* <p>This implementation calls {@code add(size(), e)}.
*
* <p>Note that this implementation throws an
* {@code UnsupportedOperationException} unless
* {@link #add(int, Object) add(int, E)} is overridden.
*
* @param e element to be appended to this list
* @return {@code true} (as specified by {@link Collection#add})
* @throws UnsupportedOperationException if the {@code add} operation
* is not supported by this list
* @throws ClassCastException if the class of the specified element
* prevents it from being added to this list
* @throws NullPointerException if the specified element is null and this
* list does not permit null elements
* @throws IllegalArgumentException if some property of this element
* prevents it from being added to this list
*/
public boolean add(E e) {
add(size(), e);
return true;
}
所以 当我们对返回的List执行add和remove方法时,就会报UnsupportedOperationException了。但是因为有set()方法,所以,我们可以修改返回的List。
5.2 我们说Arrays.asList()返回的是基于原数组的List视图, 而且修改List的元素时候,原数组的内容也会同时改变,这又是为何呢?
根据上面的代码,我们可以知道, 我们调用返回的ArrayList的set(),get(), indexOf(), contain(),size()这些方法,本质上都是去对原数组进行对应的操作。所以,我们改变返回的ArrayList中的内容的时候,原数组也会同时改变。这就是集合视图(collection view),集合了常用的方法。
5.3 为何返回的ArrayList的长度是固定的?还有为什么Arrays.asList()方法最快?
还是上面的代码,一般来说,ArrayList内部有一个对象类型数组作为实例变量来存放ArrayList中的数据。而上面的内部类中,ArrayList的这个实例变量就是a,而它只是将引用指向了原数组,并未将原数组的内容复制到a中。这样就没有进行复制操作,也没有创建新的数组对象,自然最快了。
同时,该内部类ArrayList并为提供add方法等方法,自然是无法修改ArrayList的长度。而且因为是直接将实例变量a指向原数组,我们知道数组一旦初始化后就没法修改它的大小了,所以原数组不能改变大小,自然返回的ArrayList的长度也不能改变长度,长度就只能是固定的。
本文为joshua317原创文章,转载请注明:转载自joshua317博客 https://www.joshua317.com/article/243