ArrayList for遍历删除分析

一、案例
//案例一
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("1");
        list.add("2");
        for (String item : list) {
            if ("1".equals(item)) {
                list.remove(item);
            }
        }
    } //运行不报错

//案例二
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("1");
        list.add("2");
        for (String item : list) {
            if ("2".equals(item)) {
                list.remove(item);
            }
        }
    } //运行报错Exception in thread "main" java.util.ConcurrentModificationException


二、javap反编译后字节码分析
public static void main(java.lang.String[]);
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=4, args_size=1
         0: new           #2                  // class java/util/ArrayList
         3: dup
         4: invokespecial #3                  // Method java/util/ArrayList."<init>":()V
         7: astore_1
         8: aload_1
         9: ldc           #4                  // String 1
        11: invokeinterface #5,  2            // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
        16: pop
        17: aload_1
        18: ldc           #6                  // String 2
        20: invokeinterface #5,  2            // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
        25: pop
        26: aload_1
        27: invokeinterface #7,  1            // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
        32: astore_2
        33: aload_2
        34: invokeinterface #8,  1            // InterfaceMethod java/util/Iterator.hasNext:()Z
        39: ifeq          72
        42: aload_2
        43: invokeinterface #9,  1            // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
        48: checkcast     #10                 // class java/lang/String
        51: astore_3
        52: ldc           #6                  // String 2
        54: aload_3
        55: invokevirtual #11                 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
        58: ifeq          69
        61: aload_1
        62: aload_3
        63: invokeinterface #12,  2           // InterfaceMethod java/util/List.remove:(Ljava/lang/Object;)Z
        68: pop
        69: goto          33
        72: return

    21-25行:java编译器把for循环编译成List.iterator,然后通过Iterator.hasNext,Iterator.next遍历,然后checkcast指令String类型校验

三、源码分析



1. 调用ArrayList.iterator(),返回Iterator对象
2. 标记5是 Iterator对象的remove(),标记6是 ArrayList的remove()
3. cursor是Iterator当前指针,lastRet是Iterator上次遍历的指针,modCount是ArrayList的变更次数,当add(1),add(2),remove(1)时,modCount=3

案例一分析:
    1. add(1),add(2),for遍历 : modCount=2,expectedModCount=2,cursor=0,size=2
    2. Iterator.hasNext():返回true
    3. Iterator.next():标记3的checkForComodification()校验成功,返回字符串“1”
    4. equals=true,调用标记6的ArrayList的remove():modCount=3,expectedModCount=2,cursor=1,size=1
    5. Iterator.hasNext():返回false,退出循环
    总结:根本就没有遍历第二个字符串“2”

案例二分析:
    1. add(1),add(2),for遍历 : modCount=2,expectedModCount=2,cursor=0,size=2
    2. Iterator.hasNext():返回true
    3. Iterator.next():标记3的checkForComodification()校验成功,返回字符串“1”
    4. equals=false:modCount=2,expectedModCount=2,cursor=1,size=2
    5. Iterator.hasNext():返回true
    6. Iterator.next():标记3的checkForComodification()校验成功,返回字符串“2”
    7. equals=true,调用标记6的ArrayList的remove():modCount=3,expectedModCount=2,cursor=2,size=1
    8. Iterator.hasNext():返回true
    9. Iterator.next():标记3的checkForComodification()校验失败,modCount != expectedModCount抛异常ConcurrentModificationException

总结:
    1. ArrayList.remove()方法不会更新expectedModCount,cursor,只更改了原数组,size,modCount等数据,由于数据不一致导致校验失败。
    2. Iterator.remove()方法会更新原数组,size,modCount等数据。

猜你喜欢

转载自ncs123.iteye.com/blog/2412975