java中String學習

1. String的不可變性

一旦一個String對象在內存中創建, 它將不可改變, 所有String類中方法並不是改變String對象自己, 而是重新創建一個新的String對象 .
這裏寫圖片描述
第一行在常量池中創建一個”abc”對象,
第二行進行截取, 其實是重新創建一個對象, 然後讓a重新指向這個截取對象 .
但是原來”abc”對象並沒有變化 , 只是沒有引用指向它, 最後被垃圾回收 .
也就是”abc”, 一旦創建就不會被修改 . 這就是不可變性 .
查看String源碼 :
這裏寫圖片描述
它的成員變量都是final, 尤其是value成員, 被final修飾, 表示這個變量一旦通過構造函數生成就不能被改變 .
所以String的不可變性並不是因爲類被聲明final(類被聲明final只能代表可不可被繼承), 真正決定不可變性, 是成員變量都被聲明爲final .

2. 代碼

 *常量 : final String a = "abc", 被final修飾, 那麼a就是常量.
public static void main(String[] args) {
        /**
         * 1.常量池
         * JVM存在一個常量池,其中保存很多String對象,並且可以被共享,提高效率
         * 由於String類中成員是final, 它的值一旦創建不能被修改
         * 字符串池由String類維護, 可以調用intern方法訪問字符串池 . 
         */
        // 字符串池創建一個對象
        String s1 = "abc";
        // 字符串池中存在"abc",所以這次不需要創建對象
        String s2 = "abc";
        // 所以兩個地址指向一致 . 
        System.out.println("s1 == s2:"+(s1 == s2)); // true

        /**
         * 2.new String("")
         */
        // 創建兩個對象, 一個存在字符串池中, 一個存在堆中
        String s3 = new String("abc");
        // 池中已經存在"abc"對象, 所以只在堆中創建
        String s4 = new String("abc");
        // 所以s3和s4不相等,都在堆中,指向的內存區域不同
        System.out.println("s3 == s4:"+(s3 == s4)); // false
        // 一個在pool中另一個在堆中
        System.out.println("s1 == s3:"+(s1 == s3)); // false

        /**
         * 3.常量的值在編譯時已經確定(優化)
         * 這裏"ab"和"cd"都是常量, 因此"+"之後值在編譯時確定
         * 等同於 str = "abcd"
         */
        String s5 = "ab" + "cd";
        String s6 = "abcd";
        System.out.println("s5 == s6:"+(s5 == s6)); // true
        /**
         * 4.局部變量s7,s8存儲兩個拘留字符串對象的地址 . 
         * 那麼下面(s7+s8)原理 :
         * 運行期JVM首先會在堆中創建一個StringBuilder對象,
         * 然後利用s7指向的拘留字符串完成初始化
         * 然後調用append方法完成對s8指向的字符串進行合併
         * 然後調用toString方法在堆中創建一個String對象
         * 最後將剛生成的String對象地址存放在s9中.
         * s10存儲的是字符串池中"abcd"對應的地址.
         * s9存儲是堆中"abcd"對應地址
         */
        String s7 = "ab";
        String s8 = "cd";
        String s9 = s7 + s8;
        String s10 = "abcd";
        System.out.println("s9 == s10:"+(s9 == s10)); // false

        /**
         * 5.java編譯器對String+基本類型/常量, 當成常量表達式直接求值優化
         * 運行期兩個string相加,會產生新的對象, 存在堆中
         */
        String s11 = "b";
        String s12 = "a" + s11;
        String s13 = "ab";
        //因爲s11是變量(被final修飾是常量),所以運行期纔會被解析
        System.out.println("s12 == s13:"+(s12 == s13) ); // false
        final String s14 = "b";
        String s15 = "a" + s14;
        String s16 = "ab";
        System.out.println("s15 == s16:"+(s15 == s16)); // true
    }

面試題:
曾經一個面試題 :

public static void main(String[] args) {
        String a = "hello";
        String b = "hel" + "lo";
        String c = "hel" + new String("lo");
        final String d = "lo";
        String e = "lo";
        String f = "hel" + d;
        String g = "hel" + e;
        System.out.println(a == b); // true b是常量相加
        System.out.println(a == c); // false new String會重新新建對象
        System.out.println(a == f); // true d是常量(被final修飾)
        System.out.println(a == g); // false e是變量不會編譯期優化
    }

3.以前疑惑

對於String a = “abc”, 我總在思考 a 到底是字符串常量還是變量 . 你說它是常量, 他卻沒有被final修飾, 如果說變量但是”abc”會被放在常量池中 .
最後別人一句話點醒了我, a 是變量, “abc”是常量 . 我以前老糾結在 a 上, 導致概念各種混亂 .
如果a要變成常量 , 需要被final修飾 , final String a = “abc” .

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