今天小菜去北京某知名公司面試,做了公司的面試題,然后就是輕松的面試。
面試過程中,面試官讓我講講其中一個題是怎么選的答案,代碼大致內容如下:
1 public class StringTest{ 2 public static void main(String[] args){ 3 String str = "s"; 4 5 changeStr(str); 6 7 System.out.println(str); 8 9 } 10 11 private static void changeStr(String old){ 12 old = old + "-change"; 13 } 14 15 }
真實的輸出結果應該是s,而小菜則錯誤的認為是s-change,還跟面試官講了一堆道理。
事后瞬間感覺學藝不精,羞愧難當。。。。
這個結果為什么s呢?經過查閱資料,原來是String雖然以對象的形式存在,但仍認為是基本數據類型,就像Integer、Double那樣,雖然是基本類型的包裝類,但仍然認為是基本數據類型。
既然認為是基本數據類型,因此無論在方法中如何操作,都不會影響到外界。
其實,換個角度,也可以發現這樣是錯誤的。
首先,大家都知道字符串是不可改變的,簡單理解即可,不做深入討論。
當我們把字符串當成參數傳入方法時,傳遞的是值,是一個指針,這個指針指向了堆區的真實字符串,因此在方法中可以讀到這個字符串,但是僅僅是能讀到而已,當我們試圖做如下操作時:
str = str.replace(“a”,”b”);
后邊的str中保存的是原來的指針,的確是可以讀到原來的字符串,然后執行替換操作,但是替換操作執行時,絕對不可能去修改原來的字符串,因為字符串是不可變的,因此只能是在堆區產生一個新的字符串,然后把新字符串的地址(指針)賦給str。
此時str中保存的已經不再是原來的指針,因此讀出的內容發生了變化,但不代表原來指針指向的內容發生了變化。
另外,小菜順便再補充一個知識點。
關於Integer i = 1;和Integer i = new Integer(1);的區別。
Integer i = 1;會直接從常量池中找到1,然后把地址賦給i,這樣充分利用常量池,節省內存,注意除了字符串,其他類型的常量池都是有范圍的,超范圍了失效。
Integer i = new Integer(1);這樣寫,寫多少次,就在內存中創建多少個對象,每個對象里都保存了一個數字1,因此這樣是極其浪費內存的,不推薦使用。
常量池是保存在堆中的。
小菜水平有限,不當之處多多包涵!