不可變對象是指對象的狀態在被初始化之後,在整個對象的生命週期內,不可改變。 java
一般狀況下,在java中經過如下步驟實現不可變數組
注意:不用final關鍵字也能夠實現對象不可變,使用final只是顯示的聲明,提示開發者和編譯器爲不可變。緩存
爲何String被設計爲不可變?安全
區分對象和對象的引用多線程
String s = "ABCabc"; System.out.println("s = " + s); s = "123456"; System.out.println("s = " + s);
輸出結果:佈局
爲何String對象是不可變的?性能
public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** The value is used for character storage. */ private final char value[]; /** The offset is the first index of the storage that is used. */ private final int offset; /** The count is the number of characters in the String. */ private final int count; /** Cache the hash code for the string */ private int hash; // Default to 0
在JDK1.7中,String類作了一些改動,主要是改變了substring方法執行時的行爲,這和本文的主題不相關。JDK1.7中String類的主要成員變量就剩下了兩個:spa
public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** The value is used for character storage. */ private final char value[]; /** Cache the hash code for the string */ private int hash; // Default to 0
由以上的代碼能夠看出, 在Java中String類其實就是對字符數組的封裝。JDK6中, value是String封裝的數組,offset是String在這個value數組中的起始位置,count是String所佔的字符的個數。在JDK7中,只有一個value變量,也就是value中的全部字符都是屬於String這個對象的。這個改變不影響本文的討論。 除此以外還有一個hash成員變量,是該String對象的哈希值的緩存,這個成員變量也和本文的討論無關。在Java中,數組也是對象。 因此value也只是一個引用,它指向一個真正的數組對象。其實執行了String s = 「ABCabc」; 這句代碼以後,真正的內存佈局應該是這樣的:.net
String a = "ABCabc"; System.out.println("a = " + a); a = a.replace('A', 'a'); System.out.println("a = " + a);
輸出結果:線程
String ss = "123456"; System.out.println("ss = " + ss); ss.replace('1', '0'); System.out.println("ss = " + ss);
public static void testReflection() throws Exception { //建立字符串"Hello World", 並賦給引用s String s = "Hello World"; System.out.println("s = " + s); //Hello World //獲取String類中的value字段 Field valueFieldOfString = String.class.getDeclaredField("value"); //改變value屬性的訪問權限 valueFieldOfString.setAccessible(true); //獲取s對象上的value屬性的值 char[] value = (char[]) valueFieldOfString.get(s); //改變value所引用的數組中的第5個字符 value[5] = '_'; System.out.println("s = " + s); //Hello_World }