最近,抽空把java Arrays 工具类的asList 方法做了源码分析,在网上整理了相关资料,记录下来,希望也能帮助读者!
Arrays工具类提供了一个方法asList, 使用该方法可以将一个变长参数或者数组转换成List 。
其源代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
/**
* Returns a fixed-size list backed by the specified array. (Changes to
* the returned list "write through" to the array.) This method acts
* as bridge between array-based and collection-based APIs, in
* combination with {@link Collection#toArray}. The returned list is
* serializable and implements {@link RandomAccess}.
*
* <p>This method also provides a convenient way to create a fixed-size
* list initialized to contain several elements:
* <pre>
* List<String> stooges = Arrays.asList("Larry", "Moe", "Curly");
* </pre>
*
* @param a the array by which the list will be backed
* @return a list view of the specified array
*/
@SafeVarargs
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
|
问题发现
根据上述方法的描述,我们先来编写几个例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
/**
* @author wangmengjun
*
*/
public class ArrayExample {
public static void main(String[] args) {
/**使用变长参数*/
List<String> array1 = Arrays.asList( "Welcome" , "to" , "Java" , "world" );
System.out.println(array1);
/**使用数组*/
List<String> array2 = Arrays.asList( new String[] { "Welcome" , "to" , "Java" , "world" });
System.out.println(array2);
}
}
|
运行上述程序,输出如下内容。
[Welcome, to, Java, world]
[Welcome, to, Java, world]
心血来潮,突然想在创建的列表中添加一个字符串“Cool~~~”, 走一个。
1
2
3
|
/**使用变长参数*/
List<String> array1 = Arrays.asList( "Welcome" , "to" , "Java" , "world" );
array1.add( "Cool~~~" );
|
结果,遇到一个UnsupportedOperationException异常:
1
2
3
4
|
Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.AbstractList.add(Unknown Source)
at java.util.AbstractList.add(Unknown Source)
at test.ArrayExample.main(ArrayExample.java: 36 )
|
不可思议,new ArrayList<>(a)产生的列表调用add方法,竟然遇到问题。
原因查找
那么问题来了,到底发生了什么事情?带着疑问,去查看一下Arrays.asList中使用的ArrayList到底长啥样?
原来Arrays的asList方法使用的ArrayList类是一个内部定义的类,而不是java.util.ArrayList类。
其源代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
/**
* @serial include
*/
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) {
if (array== null )
throw new NullPointerException();
a = array;
}
public int size() {
return a.length;
}
public Object[] toArray() {
return a.clone();
}
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;
}
public E get( int index) {
return a[index];
}
public E set( int index, E element) {
E oldValue = a[index];
a[index] = element;
return oldValue;
}
public int indexOf(Object o) {
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 ;
}
public boolean contains(Object o) {
return indexOf(o) != - 1 ;
}
}
|
从这个内部类ArrayList的实现可以看出,它继承了抽象类java.util.AbstractList<E>, 但是没有重写add和remove方法,没有给出具体的实现。
但是,默认情况下,java.util.AbstractList类在add、set以及remove方法中,直接会抛出UnsupportedOperationException异常。AbstractList的部分源代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
/**
* Sole constructor. (For invocation by subclass constructors, typically
* implicit.)
*/
protected AbstractList() {
}
public E set( int index, E element) {
throw new UnsupportedOperationException();
}
/**
* {@inheritDoc}
*
* <p>This implementation always throws an
* {@code UnsupportedOperationException}.
*
* @throws UnsupportedOperationException {@inheritDoc}
* @throws ClassCastException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
* @throws IllegalArgumentException {@inheritDoc}
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public void add( int index, E element) {
throw new UnsupportedOperationException();
}
/**
* {@inheritDoc}
*
* <p>This implementation always throws an
* {@code UnsupportedOperationException}.
*
* @throws UnsupportedOperationException {@inheritDoc}
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E remove( int index) {
throw new UnsupportedOperationException();
}
}
|
正是因为java.util.Arrays类的内部类ArrayList没有重写add和remove方法,所以,当我们调用其add方法时,其实就是调用了AbstractList类的add方法,结果就是直接抛出UnsupportedOperationException异常。
同理,在调用remove方法,或者调用与add、remove方法相关联的其它方法(如addAll)同样会遇到UnsupportedOperationException异常。
addAll的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
/**
* @author wangmengjun
*
*/
public class ArrayExample {
public static void main(String[] args) {
/**使用变长参数*/
List<String> array1 = Arrays.asList( "Welcome" , "to" , "Java" , "world" );
array1.addAll(Arrays.asList( "AAA" , "BBB" ));
}
}
|
1
2
3
4
5
6
|
Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.AbstractList.add(Unknown Source)
at java.util.AbstractList.add(Unknown Source)
at java.util.AbstractCollection.addAll(Unknown Source)
at test.ArrayExample.main(ArrayExample.java: 36 )
|
set的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
/**
* @author wangmengjun
*
*/
public class ArrayExample {
public static void main(String[] args) {
/**使用变长参数*/
List<String> array1 = Arrays.asList( "Welcome" , "to" , "Java" , "world" );
System.out.println(array1);
//将Java替换成hello
array1.set( 2 , "hello" );
System.out.println(array1);
}
}
|
正是由于Arrays的内部类ArrayList重写了set方法,所以上述程序能够正常运行,不会再抛出UnsupportedOperationException异常。
结果如下:
[Welcome, to, Java, world]
[Welcome, to, hello, world]
使用场景
从上述的例子和简单分析来看,Arrays工具类提供了一个方法asList, 使用该方法可以将一个变长参数或者数组转换成List 。
但是,生成的List的长度是固定的;能够进行修改操作(比如,修改某个位置的元素);不能执行影响长度的操作(如add、remove等操作)。会抛出UnsupportedOperationException异常。
Arrays.asList比较适合那些已经有数组数据或者一些元素,而需要快速构建一个List,只用于读取操作,而不进行添加或删除操作的场景。
如果,想要根据已知数组数据,快速获取一个可进行增删改查的列表List,一个比较简单的方法如下:
重新使用java.util.ArrayList包装一层。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
/**
* @author wangmengjun
*
*/
public class ArrayExample {
public static void main(String[] args) {
/**使用变长参数*/
List<String> array1 = new ArrayList<>(Arrays.asList( "Welcome" , "to" , "Java" , "world" ));
System.out.println(array1);
array1.add( "Cool~~~" );
System.out.println(array1);
}
}
|
结果如下:
[Welcome, to, Java, world]
[Welcome, to, Java, world, Cool~~~]
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!