天天看點

Java String 為什麼不可變? 真的嗎?

衆所周知:

Stirng是個不可變的類,因為使用了final來修飾(真的隻是這個一個final的功勞嗎? ),如:

Java String 為什麼不可變? 真的嗎?

又有一個衆所周知:

就是 String的本質是一個char[] 數組。

是以為了確定String真的不可變,那麼本質肯定不能變,于是乎這個char[]數組,如:

Java String 為什麼不可變? 真的嗎?

而且這個成員變量是沒有提供set和get方法。

看到這裡,其實可以知道的就是,如果這個value數組的元素被改變了,那麼String就是被改變了。

是以在String的源碼裡,諸多方法裡面都沒有涉及到直接去修改value[]的元素。

再度聚焦:

Java String 為什麼不可變? 真的嗎?

這個構造函數,一眼能看明白意思,就是通過傳遞一個char 數組,進行構造出一個新的String。

但是又細眼一看? 

Java String 為什麼不可變? 真的嗎?

Arrays的copyOf方法去實作深拷貝:

Java String 為什麼不可變? 真的嗎?

 這樣做的原因大家都知道,就是重新開辟一波新的空間,這樣防止 在後續修改傳入的char value[] 裡的元素,導緻String也跟着被修改(如果寫成 this.value=value)

霸王硬上弓:

那麼咱們就是要修改String,怎麼辦?

那肯定就是修改它的本質 char[] value的元素了。

咱們通過反射去修改String的成員變量,也就是這個本質 char數組,一起來看看:

public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {

        String testStr = "JCccc";
        System.out.println("一開始的testStr值為 : " +testStr);
        System.out.println(testStr.hashCode());
        //反射機制,擷取擷取String裡面的的value字段
        Field valueFieldOfString = String.class.getDeclaredField("value");
        //設定value屬性的通路權限為true
        valueFieldOfString.setAccessible(true);
        //擷取s對象上的value屬性的值
        char[] value = (char[]) valueFieldOfString.get(testStr);
        //改變value數組中的元素
        value[1] = 'A';
        value[2] = 'a';
        System.out.println("被操作之後的testStr為 : " +testStr);
        System.out.println(testStr.hashCode());

    }      

看一下效果:

Java String 為什麼不可變? 真的嗎?