java中ArrayList 遍历方式、默认容量、扩容机制

 

遍历

先定义ArrayList,并填充数据

                //定义集合
        ArrayList arr = new ArrayList<>();
        //添加数据
        for(int i = 0; i < 10; i ++) {
            arr.add(i);
        }        

1、下标遍历

for (int i = 0; i < arr.size(); i++) {
    System.out.println(arr.get(i));
}

2、foreEach (jdk 1.5 及以上可用)

for (int i = 0; i < arr.size(); i++) {
    System.out.println(arr.get(i));
}

3、java 8 新特性 Lambda表达式 (jdk 1.8 及其以上)

arr.forEach(x -> System.out.println(x));

4、Iteraotr迭代器

Iterator iterator = arr.iterator();
while(iterator.hasNext()) {
    System.out.println(iterator.next());
}

5、ListIterator 迭代器 (这个是List集合特有的)

//List转用迭代
ListIterator listIterator = arr.listIterator();
//从前往后
System.out.println("listIterator 从前往后 ");
while(listIterator.hasNext()) {
    System.out.println(listIterator.next());
}

//从后往前
System.out.println("listIterator 从后往前 ");
while(listIterator.hasPrevious()) {
    System.out.println(listIterator.previous());
}

默认容量,和扩容机制

默认容量为10,有图有真相:

扩容机制,先看一下扩容的源代码吧:

    //minCapacity 代表着最小扩容量
    private void grow(int minCapacity) {
        // overflow-conscious code
        //elementData 是 ArrayList存储数据的数组 这里是获取当前数组的长度
        int oldCapacity = elementData.length;
        //计算扩容后的数组长度 = 当前数组长度  + (当前数组长度 * 0.5) ;也就是扩容到当前的 1.5 倍
        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);
    }

恩,也就是说ArrayList通常的套路是当容量不足时就扩容到当前容量的 1.5被。下面我通过java反射机制证明这一点:

public static void main(String[] args) throws Exception {
        ArrayList a = new ArrayList<>();
        for (int i = 0; i < 30; i++) {
            a.add(i);
            print(a);
        }
    }
    static void print(List list) throws Exception {
        Class c = list.getClass();
        //elementData 就是ArrayList用于底层存储数据的数组,
        //我们通过观察数组长度的变化来证明我们所说的扩容机制正确性
        Field  f = c.getDeclaredField("elementData");
        //设置可访问
        f.setAccessible(true);
        //反射对象
        Object[] elementData = (Object[])f.get(list);
        System.out.println("elementData.length" + elementData.length + ",size" + list.size());
    }

下面时执行结果:

elementData.length10,size1
elementData.length10,size2
elementData.length10,size3
elementData.length10,size4
elementData.length10,size5
elementData.length10,size6
elementData.length10,size7
elementData.length10,size8
elementData.length10,size9
elementData.length10,size10
elementData.length15,size11
elementData.length15,size12
elementData.length15,size13
elementData.length15,size14
elementData.length15,size15
elementData.length22,size16
elementData.length22,size17
elementData.length22,size18
elementData.length22,size19
elementData.length22,size20
elementData.length22,size21
elementData.length22,size22
elementData.length33,size23
elementData.length33,size24
elementData.length33,size25
elementData.length33,size26
elementData.length33,size27
elementData.length33,size28
elementData.length33,size29
elementData.length33,size30

ArrayList扩容是向上取整还是向下取整?

int newCapacity = oldCapacity + (oldCapacity >> 1);

oldCapacity >> 1 就是 oldCapacity * 0.5 jdk人员将它设计成这样是为了更高的效率。记住  oldCapacity >> 1 是向下取整 。

 

原文地址:https://www.cnblogs.com/IT-CPC/p/10886007.html