qileilove

          blog已經轉移至github,大家請訪問 http://qaseven.github.io/

          再解Java中的String

          今天朋友問我String的內容是真的不可變嗎?我肯定告訴他是的?因為在我的主觀意識里String就是一個不可變的對象。于是他給我發了這段程序:
          public class StringTest {
          public static void main(String[] args) throws Exception {
          String a = "chenssy";
          System.out.println("a = " + a);
          Field a_ = String.class.getDeclaredField("value");
          a.setAccessible(true);
          char[] value=(char[])a.get(a);
          value[4]='_';   //修改a所指向的值
          System.out.println("a = " + a);
          }
          }
            看到這個簡單的程序,我笑了,你這不是從底層來修改String的值么?從這里來理解String的值肯定是可以改變的啦(我們應該始終相信String的不可變性)!接著他再給我一段程序:
          public class StringTest {
          public static void main(String[] args) throws Exception {
          String a = "chenssy";
          String b = "chenssy";
          String c = new String("chenssy");
          System.out.println("--------------修改前值-------------------");
          System.out.println("a = " + a);
          System.out.println("b = " + b);
          System.out.println("c = " + c);
          //修改String的值
          Field a_ = String.class.getDeclaredField("value");
          a_.setAccessible(true);
          char[] value=(char[])a_.get(a);
          value[4]='_';   //修改a所指向的值
          System.out.println("--------------修改后值-------------------");
          System.out.println("a = " + a);
          System.out.println("b = " + b);
          System.out.println("chenssy");
          System.out.println("c = " + c);
          }
          }

          字體:        | 上一篇 下一篇 | 打印  | 我要投稿 

            乍看這程序是異常的簡單,無非就是賦值、改值、輸出嘛!可能你現在就會毫不猶豫的說太簡單了結果就是……。但是!!你的毫不猶豫會害死你,而且你的結果很可能錯誤。那么運行結果是什么呢?
          --------------修改前值-------------------
          a = chenssy
          b = chenssy
          c = chenssy
          --------------修改后值-------------------
          a = chen_sy
          b = chen_sy
          chen_sy
          c = chen_ssy
            修改前值很容易理解,但是修改后值呢?是不是有點兒不理解呢?你可能會問:為什么System.out.println("chenssy");的結果會是chen_ssy,System.out.println("c = " + c);也是chen_ssy呢?
            要明白這個其實也比較簡單,掌握一個知識點:字符串常量池。
            我們知道字符串的分配和其他對象分配一樣,是需要消耗高昂的時間和空間的,而且字符串我們使用的非常多。JVM為了提高性能和減少內存的開銷,在實例化字符串的時候進行了一些優化:使用字符串常量池。每當我們創建字符串常量時,JVM會首先檢查字符串常量池,如果該字符串已經存在常量池中,那么就直接返回常量池中的實例引用。如果字符串不存在常量池中,就會實例化該字符串并且將其放到常量池中。由于String字符串的不可變性我們可以十分肯定常量池中一定不存在兩個相同的字符串(這點對理解上面至關重要)。
            我們再來理解上面的程序。
            String a = "chenssy";
            String b = "chenssy";
            a、b和字面上的chenssy都是指向JVM字符串常量池中的”chenssy”對象,他們指向同一個對象。
            String c = new String("chenssy");
            new關鍵字一定會產生一個對象chenssy(注意這個chenssy和上面的chenssy不同),同時這個對象是存儲在堆中。所以上面應該產生了兩個對象:保存在棧中的c和保存堆中chenssy。但是在Java中根本就不存在兩個完全一模一樣的字符串對象。故堆中的chenssy應該是引用字符串常量池中chenssy。所以c、chenssy、池chenssy的關系應該是:c--->chenssy--->池chenssy。整個關系如下:
            通過上面的圖我們可以非常清晰的認識他們之間的關系。所以我們修改內存中的值,他變化的是所有。
            總結:雖然a、b、c、chenssy是不同的對象,但是從String的內部結構我們是可以理解上面的。String c = new String("chenssy");雖然c的內容是創建在堆中,但是他的內部value還是指向JVM常量池的chenssy的value,它構造chenssy時所用的參數依然是chenssy字符串常量。

          posted on 2014-05-08 16:45 順其自然EVO 閱讀(185) 評論(0)  編輯  收藏 所屬分類: 測試學習專欄

          <2014年5月>
          27282930123
          45678910
          11121314151617
          18192021222324
          25262728293031
          1234567

          導航

          統計

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 沾益县| 太康县| 南开区| 广饶县| 安顺市| 贵溪市| 昂仁县| 宜城市| 元谋县| 中阳县| 华安县| 靖江市| 谷城县| 阿城市| 和顺县| 泗阳县| 中西区| 读书| 香格里拉县| 交城县| 盐津县| 措美县| 闽清县| 阜新| 仁化县| 巢湖市| 武宣县| 泗洪县| 达日县| 商河县| 甘泉县| 双城市| 临邑县| 临泽县| 常德市| 安顺市| 三原县| 凤冈县| 汝城县| 临澧县| 襄樊市|