ArrayList内容意外修改

时间:2013-11-12 17:58:45

标签: java collections arraylist

从我当天回来的一本旧的java认证书中拉出一个面试问题。

不想真正想要了解它是否是一个好的面试问题。它的目的是作为一个简单的健全性检查,这个人已经用Java编写了简单的集合...我没想到错误的答案,不管怎么说,他们在路上的几个步骤中弄错了...所以它达到了它的目的

令我惊讶的是,在将它放入RAD并运行它之后是第8步的输出...在addAll没有保存list2中包含的值之后,java表现得好像是list1,放了一个引用list2中的值?由于list2的清除改变了list1的内容?!?

然而,在第7步清除之前对list2的修改对列表1没有影响......我的工作现在将通过关于集合实现的文档脱轨...这不是我所期望的。 ..任何人都可以在第8步解释list1内容的原因吗?

public static void main(String[] args)
{
    List list = new ArrayList();
    System.out.println("1: List1 Post - Constructor\t\t" + list);
    System.out.println();

    list.add("1");
    System.out.println("2: List1 Post - Add 1\t\t\t\t" + list);
    System.out.println();

    list.add("2");
    System.out.println("3: List1 Post - Add 2\t\t\t\t" + list);
    System.out.println();

    list.add(1,"3");
    System.out.println("4: List1 Post - Add three at index 1\t\t" + list);
    System.out.println();

    List list2 = new ArrayList(list);
    System.out.println("5: List1 Post - list2 Constructor\t\t" + list);
    System.out.println("5: List2 Post - list2 Constructor\t\t" + list2);
    System.out.println();

    list.addAll(list2);
    System.out.println("6: List1 Post - Add list2 to list1\t\t" + list);
    System.out.println("6: List2 Post - Add list2 to list1\t\t" +list2);
    System.out.println();

    list2 = list.subList(2,5);
    System.out.println("7: List1 Post - List 2 sublist of list 2,5\t" + list);
    System.out.println("7: List2 Post - List 2 sublist of list 2,5\t" + list2);
    System.out.println();

    list2.clear();
    System.out.println("8: List1 Post - list2 clear\t\t\t" + list);
    System.out.println("8: List2 Post - list2 clear\t\t\t" + list2);
    System.out.println();
}

1: List1 Post - Constructor                 []    
2: List1 Post - Add 1                       [1]    
3: List1 Post - Add 2                       [1, 2]    
4: List1 Post - Add three at index 1        [1, 3, 2]    
5: List1 Post - list2 Constructor           [1, 3, 2]    
5: List2 Post - list2 Constructor           [1, 3, 2]    
6: List1 Post - Add list2 to list1          [1, 3, 2, 1, 3, 2]    
6: List2 Post - Add list2 to list1          [1, 3, 2]    
7: List1 Post - List 2 sublist of list 2,5  [1, 3, 2, 1, 3, 2]    
7: List2 Post - List 2 sublist of list 2,5  [2, 1, 3]    
8: List1 Post - list2 clear                 [1, 3, 2]    
8: List2 Post - list2 clear                 []

2 个答案:

答案 0 :(得分:4)

  

由于list2的清除改变了list1的内容

是。因为ArrayList.subList遵循List.subList的记录行为:

  

返回指定fromIndex(包含)和toIndex(独占)之间此列表部分的视图。 (如果fromIndex和toIndex相等,则返回的列表为空。)返回的列表由此列表支持,因此返回列表中的非结构更改将反映在此列表中,反之亦然。返回的列表支持此列表支持的所有可选列表操作。

     

此方法消除了对显式范围操作的需要(对于数组通常存在的排序)。任何需要列表的操作都可以通过传递subList视图而不是整个列表来用作范围操作。例如,以下习语从列表中删除了一系列元素:

 list.subList(from, to).clear();

具体给出了通过在子列表视图上调用clear来删除列表的一部分的示例。

答案 1 :(得分:1)

每当调用ArrayList.subList(fromIndex, toIndex)函数时,实习生都会返回SubList类的实例:

public List<E> subList(int fromIndex, int toIndex) {
        subListRangeCheck(fromIndex, toIndex, size);
        return new SubList(this, 0, fromIndex, toIndex);
    }

ArrayList类中,SubList是一个已实现的私有内部类:

private class SubList extends AbstractList<E> implements RandomAccess {
        private final AbstractList<E> parent;
        private final int parentOffset;
        private final int offset;
        int size;

        SubList(AbstractList<E> parent, int offset, int fromIndex, int toIndex) {
            // constructor assignment variable
        }
        // other implemented function
 }

这个类有几个实现的功能,包括:get(), set(int index, E e), size(), add(E e), remove(E e), removeRange(int fromIndex, int toIndex)等等;调用哪个最终会对parent AbstractList进行更改。有关您的上下文的相关信息,请参阅removeRange(int fromIndex, int toIndex)函数的实现:

protected void removeRange(int fromIndex, int toIndex) {
        checkForComodification();
        parent.removeRange(parentOffset + fromIndex,
                           parentOffset + toIndex);   // <--- removing parent
        this.modCount = parent.modCount;
        this.size -= toIndex - fromIndex;
    }

SubList扩展AbstractList类,其clear()函数实现如下:

public void clear() {
        removeRange(0, size());
    }

因此,调用clear()返回的列表实例的ArrayList.subList(fromIndex, toIndex)函数会对ArrayList本身进行更改。 documentation通过以下语句支持此实现:

  

返回指定列表中此列表部分的视图   fromIndex,inclusive,toIndex,exclusive。 (如果fromIndex和   toIndex相等,返回的列表为空。)返回的列表是   此列表支持,因此返回列表中的非结构性更改   在此列表中反映,反之亦然。 返回的列表支持   所有可选的列表操作