该文章仅是本人查看源码分析的,能力有限,如有发现错误之处,还请指出,感激不尽!
介绍内容:
- 无参构造的创建
- 扩容机制
- 删,改,查
- 内部类 Itr,ListItr,SubList 的使用
- 支持 lambda 表达式
ArrayList源码分析
案例介绍:
// 扩容案例:
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(4, 5);
list.forEach(System.out::println);
List<Integer> list = new ArrayList<>(3);
//提问:超过了设置的容量大小,会不会报错?
// fast-fail案例:
List<Integer> list = new ArrayList<>(3);
list.add(1);
list.add(2);
list.add(3);
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()) {
Integer next = iterator.next();
list.add(6);
System.out.println("next = " + next);
}
// 提问:在迭代器遍历时,添加元素时,会不会受到影响?
变量:
transient Object[] elementData //存储ArrayList元素
private int size; //ArrayList的大小
1、未设置初始值时的构造
例如:给 list 分配一个空数据的对象数组 List<Integer> list = new ArrayList<>();
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
2、扩容机制
空数据数组添加元素时,默认分配10的容量
private static final int DEFAULT_CAPACITY = 10;
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
- 单个添加元素,当 size 大于 elementData 长度时,会扩容成原来容量大小的1.5倍
- 添加多个(n)元素,当 size 大于 elementData 长度的1.5倍时,会扩容成 size 大小的容量
- 添加元素扩容后,如果扩容后的大小超过了 MAX_ARRAY_SIZE(2^31-1-8)时,会判断当前 size 是否超过 MAX_ARRAY_SIZE
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0)
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
}
3、查,改,删
指定 index 做操作时,会对 index 做范围校验,使用 rangeCheck(),存在数据越界异常 -- IndexOutOfBoundsException
- 查找元素,
get(int index) - 修改元素,
set(int index, E element) - 删除元素,
remove(int index),remove(Object o)
补充知识点
/**
* @param src 源数组
* @param srcPos 源数组要复制的起始位置
* @param dest 目的数组
* @param destPos 目的数组放置的起始位置
* @param length 复制的长度
*/
System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
4、内部类 Itr,ListItr,SubList 的使用
- Itr 与 ListItr 都是迭代器,源于 Iterator 与 ListIterator,区别是 ListIterator 增加了部分方法,迭代器中包含属性 expectedModCount = modCount,在调用 next() 时需要判断 modCount 是否改变,如果有改变则会抛异常,modCount 用于记录集合被修改的次数
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
请参考文档:blog.csdn.net/weixin_3924…
- SubList 是 ArrayList 中的视图,使用
subList(int fromIndex, int toIndex)获取数组中的 [fromIndex,toIndex)的视图,但是调用该视图中的方法依然可以操作原数组中的数据,但是对 ArrayList 进行添加、删除的操作之后,在操作 subList 会抛出异常
- 支持stream的方法(后续文章详细介绍)
jdk1.8 引入了 stream,掌握集合中的流方法有助于开发高质量代码,简单介绍几个常用的方法
- forEach():集合元素遍历,代替 for 循环 例如:
List<Integer> list = Arrays.asList(1,2,3);
list.forEach(System.out::println);
- filter():对流中的数据做筛选,从流中排查某些元素 例如:
list = list.stream().filter(item -> Objects.equals(item, 2)).collect(Collectors.toList());
- map():将元素转换成其他形式或提取信息 例如:
List<Person> list = new ArrayList<>();
list.add(new Person("zhangsan", 11));
list.add(new Person("lisi", 13));
list.add(new Person("wangwu", 15));
List<Integer> ageList = list.stream().map(Person::getAge).collect(Collectors.toList());
- flatMap():流的扁平化
List<Integer> list1 = Arrays.asList(1,2,3);
List<Integer> list2 = Arrays.asList(4,5,6);
List<int[]> collect = list1.stream().flatMap(i -> list2.stream().map(j -> new int[]{i, j})).collect(Collectors.toList());
其他补充:
writeObject(java.io.ObjectOutputStream s)
readObject(java.io.ObjectInputStream s)用于ArrayList的序列化与反序列化, 处理非static与transient修饰字段