Java Collections - ArrayList
2016-01-24 17:26
489 查看
ArrayList
ArrayList内部使用动态数组的形式来保存数据,每次添加元素的时候,会插入到数组尾部。数组大小不够时,会扩容。与ArrayList相关的还有一个LinkedList,内部用链表来存储数据。
初始化
初始化一个ArrayList的方法如下:ArrayList<Integer> numbers = new ArrayList<>();
如果不指定大小,默认的数组大小是10。
这个类里面定义了几个成员变量
/** * Default initial capacity. * 数组的默认大小 */ private static final int DEFAULT_CAPACITY = 10; /** * Shared empty array instance used for empty instances. * 数组里没有元素时的空数组 */ private static final Object[] EMPTY_ELEMENTDATA = {}; /** * The array buffer into which the elements of the ArrayList are stored. * The capacity of the ArrayList is the length of this array buffer. Any * empty ArrayList with elementData == EMPTY_ELEMENTDATA will be expanded to * DEFAULT_CAPACITY when the first element is added. * 存储数据的地方,如果调用无参构造函数,开始时指向EMPTY_ELEMENTDATA,添加元素,大小就会扩展到10;如果调用有参构造参数,就会指向一个初始化大小的数据。 */ private transient Object[] elementData; /** * The size of the ArrayList (the number of elements it contains). * 数组里真实存储的元素个数 * @serial */ private int size; //记录了ArrayList被修改的次数,在高并发的时候,子类可以通过这个参数来判断普通数组时,是不是被其他线程修改了,抛出ConcurrentModificationException。没有深入研究 protected transient int modCount = 0;
添加元素
用add方法往里面添加元素,会加在数据的最尾部。numbers.add(10); numbers.add(100); numbers.add(150);
在添加元素之前,会先判断数据的空间是否充足。
public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; }
ensureCapacityInternal方法会保证数据的大小。
private void ensureCapacityInternal(int minCapacity) { //EMPTY_ELEMENTDATA是一个空数组,当ArrayList里没有元素时,elementData指向空数组,这个可以不占用空间。 //取默认大小和minCapacity中较大的那个,默认大小是10 if (elementData == EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } //保证数组的大小 ensureExplicitCapacity(minCapacity); } private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code //如果当前elementData的大小比需要的最小容量还小,就要调用grow方法来扩充容量。 if (minCapacity - elementData.length > 0) grow(minCapacity); }
grow方法用来扩容,扩大到原始大小的2.5倍。使用了位移的方法来加快运算速度。
private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; //原始容量的2.5倍 int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; //取最小容量 //如果超过了最大容量(Integer.MAX_VALUE - 8),就使用Integer.MAX_VALUE if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: //将老数组上的元素拷贝到一个新数组上,这个是有时间开销的。 elementData = Arrays.copyOf(elementData, newCapacity); }
在使用ArrayList的时候,最好估算好大小,分配合适的空间。否则在扩容的时候会频繁的拷贝数据,影响性能。
遍历元素
遍历的方法有两种。使用index遍历和for each遍历。System.out.println("#1: indexed loop for iteration"); for (int i = 0; i < numbers.size(); i++) { System.out.println(numbers.get(i)); } System.out.println("2#: iteration"); for (Integer value : numbers) { System.out.println(value); }
它们的性能如何呢?对于ArrayList,index遍历的性能要更优,但是也优不了多少。
在Java里,foreach语法是iterator的变形
for(int i : weights) { sum += i; }
等同与:
for(Iterator<Integer> i = weights.iterator(); i.hasNext()) { sum += i.next(); }
删除元素
在ArrayList删除元素的耗时与位置有关。删除最后一个元素:直接把数组的大小减1就行。
删除中间某个元素:需要将它后面的部分都拷贝一次,开销比较大。
因此尽量不要在ArrayList上频繁删除元素。
相关文章推荐
- JavaEE Tutorials (20) - 企业应用安全入门
- 小知识点-JAVA
- 重学Java系列(一) -- static、final
- 正则表达式校验身份证号
- JavaEE Tutorials (19) - Web应用安全入门
- JavaEE Tutorials (18) - Java EE平台安全介绍
- JavaEE Tutorials (17) - Java消息服务示例
- JavaEE Tutorials (16) - Java消息服务概念
- 再淡spring jdbc 连接池断开重连设置
- JavaEE Tutorials (15) - 对Java持久化API应用使用二级缓存
- spring整合Hibernate
- JavaEE Tutorials (14) - 用实体图创建获取计划
- JavaEE Tutorials (13) - 使用锁定控制对实体数据的并发访问
- Struts2原理
- Java中常见的时间处理
- JavaEE Tutorials (12) - 创建和使用基于字符串的Criteria查询
- JavaEE Tutorials (11) - 使用Criteria API创建查询
- Java对List集合的排序
- 关于SpringMVC 400 Bad Request 问题
- JavaEE Tutorials (10) - Java持久化查询语言