首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

Java 容器源码分析之 ArrayList(2)

Java 容器源码分析之 ArrayList(2)

扩容ArrayList既然是基于可变数组的,那么在底层数组的存储容量不足时肯定会进行扩容操作,以改变容器的容量。扩容的操作是通过下面的代码进行实现的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/**
* Increases the capacity of this <tt>ArrayList</tt> instance, if
* necessary, to ensure that it can hold at least the number of elements
* specified by the minimum capacity argument.
*/
public void ensureCapacity(int minCapacity) {
    int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
        // any size if not default element table
        ? 0
        // larger than default for default empty table. It's already
        // supposed to be at default size.
        : DEFAULT_CAPACITY;

    if (minCapacity > minExpand) {
        ensureExplicitCapacity(minCapacity);
    }
}

private void ensureCapacityInternal(int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }

    ensureExplicitCapacity(minCapacity);
}

private void ensureExplicitCapacity(int minCapacity) {
    modCount++;

    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*/
private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    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);
}

private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE) ?
        Integer.MAX_VALUE :
        MAX_ARRAY_SIZE;
}

public int size() {
    return size;
}

public boolean isEmpty() {
    return size == 0;
}
这一段代码的注释很清楚了,大致解释一下:ensureCapacity方法可供外部调用,而ensureCapacityInternal则仅供内部调用,都是要确保当前容器能够容纳给定数量的元素,它们都会调用ensureExplicitCapacity方法;在每次调用ensureExplicitCapacity方法时,会将modCount 的值加1,表明 ArrayList 发生了结构化的修改,然后根据当前数组能容纳的元素数量来决定是否需要调用grow方法来调整数组的大小;grow方法负责调整数组的大小,注意每次调整时将容量扩大为当前容量的1.5倍(oldCapacity + (oldCapacity >> 1)),如果还是不能满足容量要求,就按照所需的最小容量来分配,然后将原数组中的元素复制到新数组中。ArrayList 能够支持的最大容量为 int 值的上限,超过会报OutOfMemoryError异常。
这里有一个奇怪的地方在于,modCount 的值会在 ensureExplicitCapacity 方法中加1。前面已经说过,modCount用来记录容器发生结构化修改的次数,按道理来说实在加入或移除元素是才会修改的,为什么会在这里调用呢。后面我们会看到,每次新加入元素时,ensureExplicitCapacity 都会被调用,因而可以将modCount的修改放在此方法中,就不必在 add 及 addAll 方法中进行修改了。
返回列表