面向對象2-List list中的這個list到底是不是一個List

相信很多人在初學java的時候,都會遇到一個同樣的問題,就是當我們認爲自己已經把一個list加入到List<List<T>> 中去了,爲什麼最後結果發現不對。如這個例子。

List<List<Integer>> res = new ArrayList<List<Integer>>();

List<Integer> list = new ArrayList<Integer>();

for (int i = 0; i < 3; i++) {

list.add(i);

res.add(list);

}

return res;

假設,我們想得到的數據是{ {0}, {0, 1}, {0, 1, 2} } 這樣的結果,請問這個res是不是得到了這樣的結果?

如果不是,

請問,res.size()==?,然後res裏的數據是什麼樣的?


首先,這裏只通過ArrayList構造器創建了一個List的實例,也就是說整個過程中,只有一個真正意義上的List Object,但是res.size() == 3。

不僅如此,res == { {0, 1, 2}, {0, 1, 2}, {0, 1, 2} };


本人在剛開始學習的過程中,難以預計到這樣的結果。

其實原因也很簡單。在java中,有不同的數據類型。其中,原始數據類型之間是值傳遞,而其他的數據類型是引用傳遞。

而在java中,一個Object或者Array被創建時,將會在堆中分配內存,同時產生一個該Object或者Array的引用變量(reference)放在函數的棧內存中。

也就是說,list只是一個相對應類別的引用名稱,或者說是一個句柄(handle)。

當res.add(list)發生時,一個引用變量被傳入。在for循環中,被傳入了三次。即使在傳入的過程中,list所指向的Object所包含的內容不同,卻是同一個具體的實例。

最終res裏包含的就是三次在return位置時,list所指向的Object的值,也就是 {0, 1, 2}。

爲了避免這樣的結果導致實際工作中的錯誤,一般而言,

res.add(new ArrayList<Integer>(list));

在加入一個引用型變量時,產生一個新的Object來避免問題的出現。

List<List<Integer>> res = new ArrayList<List<Integer>>();

List<Integer> list = new ArrayList<Integer>();

for (int i = 0; i < 3; i++) {

list.add(i);

res.add(new ArrayList<Integer>(list));

}

return res;

// res == { { 0 }, { 0, 1 }, { 0, 1, 2} }





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章