这是崩溃日志.png今天在看友盟控制台的时候发现一个崩溃,报错的是
ArrayList add()
数组指针越界??ArrayList
不是动态扩容的吗?怎么会数组越界呢??带着问题,开始了今天的文章。
看到这个错误,我第一时间就去谷歌了一下,找到了这篇文章 :
ArrayList在多线程调用Add()添加元素时的下标越界问题(java.lang.ArrayIndexOutOfBoundsException)
基本上这个文章已经告诉了我们答案,为什么 ArrayList
集合在add
的时候会数组越界。
我这里出现这个问题的原因是在网络请求的时候,使用了线程池去发送请求网络数据,在得到结果之后解析结果。
这里出错就是在解析结果的时候没有做同步操作引起的。
之所以要做同步操作是因为我多做了一步操作,就是网络不好的时候会多发几次网络请求,有时候可能已经返回了结果但是还是会再次发一次请求。
(吐槽一下,这个项目的网络请求是公司自己封装的 HttpConection 实现的,用起来还是挺费劲的)
上面的文章说了是线程同步的问题,但是作者没给出答案,我这里想到了几个解决办法。
- 给方法加锁
synchronized
- 使用
Vector
替代ArrayList
- 使用
CopyOnWriteArrayList
替代ArrayList
PS: 以上几种实现方式各有优缺点,可在文末找到链接介绍。
我这里的解决办法是给方法加上 synchronized 锁,然后将用 Vector 替代了 ArrayList。
之前在听一个算法课的时候有听到
arrayList
的默认长度是10
,且每次扩容都是原来的1.5
倍,趁着这次看源码,我就去找了对应的实现。
默认容量是 10
private static final int DEFAULT_CAPACITY = 10;
elementData
是个动态数组,扩容为原来 1.5
倍
ArrayList 常用方法
在验证了以上两点之后,我在源码中又看到了常见的一些方法,结合网上的归纳整理如下:
- 增加元素到链表中
boolean add(Element e)
增加指定元素到链表尾部.
void add(int index, Element e)
增加指定元素到链表指定位置.
- 从链表中删除元素
void clear()
从链表中删除所有元素.
E remove(int index)
删除链表中指定位置的元素.
protected void removeRange(int start, int end)
删除链表中从某一个位置开始到某一个位置结束的元素。
- 获取链表中的元素
E get(int index)
获取链表中指定位置处的元素.
Object[] toArray()
获取一个数组,数组中所有元素是链表中的元素.(即将链表转换为一个数组)
- 修改某个元素
E set(int index, E element)
将链表中指定位置上的元素替换成新元素。
- 搜索元素
boolean contains(Object o)
如果链表包含指定元素,返回true.
int indexOf(Object o)
返回元素在链表中第一次出现的位置,如果返回-1,表示链表中没有这个元素。
int lastIndexOf(Object o)
返回元素在链表中最后一次出现的位置,如果返回-1,表示链表中没有这个元素。
- 检查链表是否为空
boolean isEmpty()
返回true表示链表中没有任何元素.
- 获取链表大小
int size()
返回链表长度(链表包含元素的个数).
遍历
获取链表之后我们经常会对其进行遍历,这里列举出三种遍历方式。
第一种,通过迭代器遍历。即通过 Iterator
去遍历。
第二种,随机访问,通过索引值去遍历。
image.png由于
ArrayList
实现了RandomAccess
接口,它支持通过索引值去随机访问元素。
第三种,for
循环遍历。如下:
三种遍历方式中耗时最短的是使用随机访问,使用迭代器遍历的耗时最长。
参考
ArrayList用法
Java入门系列:实例讲解ArrayList用法
Vector 详解
Java 集合系列06之 Vector详细介绍(源码解析)和使用示例
ArrayList 详解
Java 集合系列03之 ArrayList详细介绍(源码解析)和使用示例
CopyOnWrite 详解
CopyOnWrite 详解
本文完~,欢迎你留言和我一起讨论。
网友评论