从我当天回来的一本旧的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 []
答案 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相等,返回的列表为空。)返回的列表是 此列表支持,因此返回列表中的非结构性更改 在此列表中反映,反之亦然。 返回的列表支持 所有可选的列表操作
。