Re: [問題] 請教String的問題

作者: kdok123 (小天)   2014-12-18 20:00:42
非常感謝大家的熱心回應,我完全理解了
現在只剩一個小問題想問...
ex1:
String a = "Hello";
a = "kdok123";
這個結果是new了兩個String的空間在Heap
ex2:
Interger a = 3;
a = 4;
結果是new了一個Interger的空間在Heap,a指向的值從3改成了4
以上兩個例子體現了String的不可變性
請問例子的觀念是對的嗎?
另外還有一個小疑惑:為什麼java要定義String的不可變性呢?
除了不斷的增加heap和GC的負擔之外我想不到其他好處欸...
作者: Kenqr (function(){})()   2014-12-18 20:26:00
輸出2次一樣是因為pass by reference,和不可變無關ex2的a會指到另一個不同的位置,用任何class都會這樣
作者: ssccg (23)   2014-12-18 20:33:00
你根本沒有懂,就說你的結果跟不可變性"完全"沒關係String不可變是String不提供任何方法修改它裡面char array存的值,要修改一定是產生新的String object剛進method的str2指向的就是完全同一個String並沒另外開一個空間,是之後你自己開新的空間放新的String="abc"相當於=new String(new char[] {'a','b','c'})可變性的意義在於如果有個MutableString class你可以用str2.setValue("abc")去改object的內容而不用寫成str2 = new MutableString("abc")只要用的是 = new XXX(),不管哪個class都是一樣的結果只要你用的是 = 都是不會變的,因為 = 不是改object裡的值而是改reference指向的位址只有primitive type的時候用 = 才是改值
作者: kdok123 (小天)   2014-12-18 20:53:00
String="abc"的意思是若"String pool沒有"abc",則創造一個新空間存放abc,否則指向abcString ob = new String("abc")的意思是"不管String pool裡有沒有abc,都創造一個空間存放abc因為immutable的特性,才會造成上面的結果,否則任何的賦值動作都會覆蓋原本的值http://www.cnblogs.com/fguozhu/articles/2661055.html
作者: ssccg (23)   2014-12-18 20:57:00
覆蓋原本的值也是覆蓋reference,而不是覆蓋value
作者: kdok123 (小天)   2014-12-18 20:57:00
參考連結的觀念的
作者: kdok123 (小天)   2014-12-18 21:02:00
這邊我認為是immutable的關係,若今天是mutable就改得到或許等我試試上面連結的atomic wrapper class?android studio沒有把那個class import進來不能測試...
作者: ssccg (23)   2014-12-18 21:05:00
我是不知道你打算怎麼試,但是除了primitive的autowrapper還有String literal("...")以外,其他type都很清楚就是換了物件啊...如果你有學過C++,java的reference type基本上就是pointer如果是C++的pass by reference(&),即使物件是mutable還是可直接改caller func中那個reference的值(指向的位址)或是你可以去用C#試,C#的reference type跟java一樣String也是Immutable,但是方法可以pass by reference你的ex1用C# pass by ref版 http://ideone.com/Miptpm
作者: kdok123 (小天)   2014-12-18 21:43:00
Hi,因為java這邊是auto-boxing的,所以以c++的觀念來說pointer是指向同一個地方,要修改值的但因為immutable的特性,才沒有修改成功我只是想說,如果你認為java的reference就是c++的pointer那在auto-boxing的結果下,你應該會覺得值要被修改才對
作者: ssccg (23)   2014-12-18 23:20:00
immutable不是不能修改reference值,是不能修改object裡面的data,你還是直接看上面的C#的範例...既然會C++也給你一個C++版 http://ideone.com/DSzyGI不是我覺得,是java的reference變數真的就是pointer改是改pointer指的位址,但是在call by value的時候改不動caller func裡面的pointer變數很明顯就call by value/call by reference的差別啊..btw auto-boxing是指對只吃Object子class的地方(如list)自動包wrapper,unboxing是在assign給primitive變數的時候自動改為取值(.xxxValue)而不是assign reference如果全程都是直接用Integer這個class,那與一般class沒差別把Integer assign給Integer變數是不會有auto-box/unbox行為
作者: bleed1979 (十三)   2014-12-19 07:28:00
看完這整個討論串,好難過,想去renew Java 7的認證。
作者: kdok123 (小天)   2014-12-19 09:22:00
我很想講得更清楚一點,但前面darkk6大已經畫得很清楚了這邊的重點應該是immutable/mutable的差別才對如果這邊是mutable的class,你說的caller func的pointer變數就會被改到因為我認為這邊的觀念很重要,才會一直強調,或許其他版友可以加入一起討論,來釐清這個問題?
作者: ssccg (23)   2014-12-19 09:41:00
就算是mutable class,caller func的pointer還是不會改到因為是pass by value,在傳入時只是複製pointer的值d大的圖我只能說 // 因為字串的 Immutable... 這句完全錯誤不管是什麼class,用assign (=)的方式,改的永遠都是str2指向的位址(pointer value)而已,原本的那個object不會被動到要動原本的object就要用它的method/fieldimmutable意義在於原本的object沒有公開的改值method/field用pointer來說的話就是要改object的值一定要先dereference用=只會改pointer存的位址你好像幻想lhs如果是個mutable reference type變數用=會自動把lhs指向的物件中代表value的field拿出來,然後把rhs expression物件中代表value的field裡存的值放進去從你上面提auto-boxing可以看出來,可是實際上沒這回事=只會把lhs reference直接改成指向rhs的結果物件lhs原本指向什麼完全沒差,在=的動作中那個物件根本沒出場=只有在lhs是primitive type的時候才是賦值(因為primitive)type才有所謂value,如果lhs是reference type,他指向的物件不一定有所謂的value,這時做的都只是改指向的物件

Links booklink

Contact Us: admin [ a t ] ucptt.com