java 数组 源码_java 源码分析Arrays.asList方法详解

最近,抽空把java Arrays 工具类的asList 方法做了源码分析,在网上整理了相关资料,记录下来,希望也能帮助读者!

Arrays工具类提供了一个方法asList, 使用该方法可以将一个变长参数或者数组转换成List 。

其源代码如下:

/**

* 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}.

*

*

This method also provides a convenient way to create a fixed-size

* list initialized to contain several elements:

*

 
 

* List<String> stooges = Arrays.asList("Larry", "Moe", "Curly");

*

*

* @param a the array by which the list will be backed

* @return a list view of the specified array

*/

@SafeVarargs

public static List asList(T... a) {

return new ArrayList<>(a);

}

问题发现

根据上述方法的描述,我们先来编写几个例子:

/**

* @author wangmengjun

*

*/

public class ArrayExample {

public static void main(String[] args) {

/**使用变长参数*/

List array1 = Arrays.asList("Welcome", "to","Java", "world");

System.out.println(array1);

/**使用数组*/

List array2 = Arrays.asList(new String[] {"Welcome", "to","Java", "world"});

System.out.println(array2);

}

}

运行上述程序,输出如下内容。

[Welcome, to, Java, world]

[Welcome, to, Java, world]

心血来潮,突然想在创建的列表中添加一个字符串“Cool~~~”,  走一个。

/**使用变长参数*/

List array1 = Arrays.asList("Welcome", "to","Java", "world");

array1.add("Cool~~~");

结果,遇到一个UnsupportedOperationException异常:

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类。

其源代码如下:

/**

* @serial include

*/

private static class ArrayList extends AbstractList

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[] 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

if (a[i]==null)

return i;

} else {

for (int i=0; i

if (o.equals(a[i]))

return i;

}

return -1;

}

public boolean contains(Object o) {

return indexOf(o) != -1;

}

}

从这个内部类ArrayList的实现可以看出,它继承了抽象类java.util.AbstractList, 但是没有重写add和remove方法,没有给出具体的实现。

但是,默认情况下,java.util.AbstractList类在add、set以及remove方法中,直接会抛出UnsupportedOperationException异常。AbstractList的部分源代码如下:

public abstract class AbstractList extends AbstractCollection implements List {

/**

* Sole constructor. (For invocation by subclass constructors, typically

* implicit.)

*/

protected AbstractList() {

}

public E set(int index, E element) {

throw new UnsupportedOperationException();

}

/**

* {@inheritDoc}

*

*

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}

*

*

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的例子:

/**

* @author wangmengjun

*

*/

public class ArrayExample {

public static void main(String[] args) {

/**使用变长参数*/

List array1 = Arrays.asList("Welcome", "to", "Java", "world");

array1.addAll(Arrays.asList("AAA", "BBB"));

}

}

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的例子:

/**

* @author wangmengjun

*

*/

public class ArrayExample {

public static void main(String[] args) {

/**使用变长参数*/

List 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包装一层。

/**

* @author wangmengjun

*

*/

public class ArrayExample {

public static void main(String[] args) {

/**使用变长参数*/

List 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~~~]

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值