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}. * * <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); }
问题发现
根据上述方法的描述,我们先来编写几个例子:
/** * @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~~~”, 走一个。
/**使用变长参数*/ list<string> 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<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的部分源代码如下:
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的例子:
/** * @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")); } }
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<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包装一层。
/** * @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~~~]
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!