2015-07-21 47 views
3

我知道當你通過引用傳遞它們時,Java中的Collections是可變的。
我想知道在它的原始列表和子列表的內存地址中究竟發生了什麼。
子列表和原始列表是否引用同一個對象?爲什麼更改子列表會反映在原始列表中?

以下是代碼示例反映子表作出主要原始列表的變化。

List<String> list = new ArrayList<String>(); 
list.add("1"); 
list.add("2"); 
list.add(1, "3"); 

List<String> list2 = new LinkedList<String>(list); 

list.addAll(list2); 

list2 = list.subList(2, 5); 
list2.clear();    //Changes are made to list 

System.out.println(list); 

回答

7

作爲每JavaDoc對此事:

列表子列表(INT的fromIndex, INT toIndex)

返回指定的fromIndex之間的這種列表的該部分的視圖,包括,並以指數, 排他。 (如果fromIndex和Index相等,則返回的列表爲 爲空。)返回的列表由此列表支持,因此返回列表中的非結構化 變化反映在此列表中,反之亦然 。返回的列表支持此列表支持的所有可選列表 操作。

子列表將指向原始列表中的相同元素,因此,通過子列表所做的任何更改都會反映在原始列表中,因爲您正在更改相同的對象。

編輯:根據您的評論,假設original list有以下參考文獻:0x00 0x01 0x02 0x03 0x04 0x05和這些映射到內存中存在對象的位置。

在上面的操作sublist(0, 2)將生成一個列表,其中包含指向以下存儲單元0x00 0x01 0x02 0x03的指針,這些指針與original list中的指針相同。

這是什麼意思是,如果你做sublist.get(0).setFoo(foo),這將反過來尋找目標0x00並設置一些屬性。然而,0x00也正在original list爲什麼改變子列表表示,由於這兩個列表指向同一個對象你會改變源列表參考,這是。如果您通過original list更改元素,也是一樣。

+0

我知道,我已經閱讀過。但是在內存中究竟發生了什麼? –

+0

你是指什麼在內存中發生什麼?就像任何引用同一事物的東西一樣。這裏沒有什麼特別 –

+0

@ShubhamKharde:我試圖擴大我的答案。如果你仍然有問題,你將需要看看如何引用一般工作。 – npinti

2

檢查這個link

SubList返回指定fromIndex(包含)和toIndex(不包括)的 之間的此列表部分視圖。 (如果fromIndex 和toIndex相等,則返回的列表爲空。)返回的列表 通過這個列表支持,所以在返回的列表 非結構變化將反映在此列表中,並且反之亦然。返回的列表支持 此列表支持的所有可選列表操作。

所以你的列表2就是你的原單list.That的子視圖是爲什麼,當你清除列表2,你是用原list.Check失去相應值這個代碼。

public static void main(String[] args) 
    { 
     List<String> list = new ArrayList<String>(); 
     list.add("1"); 
     list.add("2"); 
     list.add(1, "3"); 
     List<String> list2 = new LinkedList<String>(list); 
     list.addAll(list2); 
     System.out.println(list); 
     list2 = list.subList(2, 5); 
     System.out.println(list2); 
     list2.clear();    //Changes are made to list1 
     System.out.println(list); 

    } 

O/P

[1, 3, 2, 1, 3, 2] 
[2, 1, 3] 
[1, 3, 2] 
1

在線路

list2 = list.subList(2, 5); 

您所呼叫的ArrayListsubList方法從list稱作。它的代碼看起來像這樣

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

所以確認有效範圍列表2將存儲

new SubList(this, 0, fromIndex, toIndex); 

其中private class SubList extends AbstractList<E>的內部ArrayList定義的類與此構造的代碼看起來像這樣

SubList(AbstractList<E> parent, 
     int offset, int fromIndex, int toIndex) { 
    this.parent = parent; 
    this.parentOffset = fromIndex; 
    this.offset = offset + fromIndex; 
    this.size = toIndex - fromIndex; 
    this.modCount = ArrayList.this.modCount; 
} 
結果後

所以其parent字段將存儲參考原始ArrayListnew SubList(this, ...))。

現在當你調用

list2.clear(); 

代碼通過SubListAbstractList繼承clear()方法將被調用

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

其中它將在內部調用removeRange覆蓋在SubList

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

所以你看到的那樣,結果你調用

parent.removeRange(parentOffset + fromIndex, 
        parentOffset + toIndex); 

這裏你還記得parent持有參考ArrayList的上subList被調用。所以通過調用clear有效地從您創建子列表的原始列表中調用removeRange

+0

謝謝。人們只是不想深入,如果他們的回答不被接受,他們會低估這個問題。對那些低估了這個問題的人來說,這是我期待的答案,他們必須堅持所提出的問題。 –

+1

@ShubhamKharde人們通常不會僅僅因爲他們的回答沒有被接受而反對投票,而是他們認爲問題不清楚或者不包含某些證據或研究。說實話,我也不確定這是否是你正在尋找的答案,但是因爲我決定刷新我關於收藏的記憶是件好事,所以我決定做一些研究並將它們作爲答案發布。 – Pshemo

+0

@ShubhamKharde無論如何,歡迎您:) – Pshemo

相關問題