list add元素覆蓋之前元素問題思考


  最近碼牆時發現了一個很有意思的問題,定義一個引用對象,如果在循環外面定義對象,在循環里list.add(對象),最后的結果卻是所有的對象值都是一樣的,即每add一次,都會把之前所有的數據覆蓋掉,蠻有趣的,在網上輕松的搜到了答案,把對象在循環里new就行了,問題雖然解決了,但感覺這里面包含了一些.net底層存儲的知識,有關於引用類型和值類型的存儲方式問題,寫了個demo總結了一下,水平,有大牛發現demo中有不足之處還請指正。

  如下面兩圖:

圖1:在外面定義對象a,調試界面中可以看到,i=4時,之前list中所有對象都被覆蓋了

圖2:在循環里定義對象a,不會被覆蓋

  又用值類型(int,short之類的)試了一下,在循環外面不會被覆蓋,結果就不截圖了,實驗了以后,用一個大牛總結的一句話來說就是:對於List<T>來說,如果T是引用類型,那保存的是引用,如果是值類型,保存的是值本身!

  但是上面的總結中有個特列:string類型。string在.net中很特殊,.net官方把它歸到了引用類型中,但它卻和值類型特別相似,具體講解參考園友停留的風的這篇文章:http://www.cnblogs.com/yank/archive/2011/10/24/2204145.html。

  用string實驗結果如下:

顯而易見,string不會覆蓋之前的數據,是引用類型中的特列。

  深入的思考了一下覆蓋的原因(水平有限,歡迎大家補充),應當如下:

1.對於引用類型,在循環外new了 a 對象后,這個對象的引用地址就確定了,執行到第二次list.add()時,list[0]中保存的a對象和新加的list[1] a對象是同一個對象,使用的是同一個地址,也就是說在添加list[1]是,list[0]也被修改了,因為它倆指針指向同一個地址,同樣,后面添加的都會修改前面所有對象,結果就是list最后所有數據都是最后的list[end_num]。

2.string也是引用對象,有唯一的引用地址(假設分配的是address1),但當add list[1]的時候(str值改變時),.net會檢查內存,發現不等於之前的字符串(list[1]不等於list[0]),.net會給原來的str重新分配內存空間address2,存儲list[0],而list[1]使用原來的空間address1。這樣使得每次list.add時都不會覆蓋之前的元素,因為它們使用的是不同的地址空間。

  這也解釋了我之前socket項目中接收數據是用StringBuilder,而不是string,每次改變string時,會消耗一份內存,socket接收中頻繁的處理string對象,會消耗大量的內存。

感覺這次小實驗挖出了很多東西,要深入研究一下。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM