標籤:緩衝池 java string 記憶體
java的虛擬機器在記憶體中開闢出一塊單獨的地區,用來儲存字串對象,這塊記憶體地區被稱為字串緩衝池。那個java的字串緩衝池是如何工作的呢?
String a = "abc";String b = "abc";String c = new String("xyz");
例如上邊的代碼:
String a = “abc”;
建立字串的時候先尋找字串緩衝池中有沒有相同的對象,如果有相同的對象就直接返回該對象的引用,如果沒有相同的對象就在字串緩衝池中建立該對象,然後將該對象的應用返回。對於這一步而言,緩衝池中沒有abc這個字串對象,所以首先建立一個字串對象,然後將對象引用返回給a。
String b = “abc”;
這一句也是想要建立一個對象引用變數b使其指向abc這一對象。這時,首先尋找字串緩衝池,發現abc這個對象已經有了,這是就直接將這個對象的引用返回給b,此時a和b就共用了一個對象abc,不過不用擔心,a改變了字串而影響了b,因為字串都是常量,一旦建立就沒辦法修改了,除非建立一個新的對象。
String c = new String(“xyz”);(這種構造方法的實現見附錄)
尋找字串緩衝池發現沒有xyz這個字串對象,於是就在字串緩衝池中建立了一個zyx對象然後再將引用返回。
從上邊的分析可以看出,當new一個字串時並不一定是建立了一個新的對象,有可能是與別的引用變數共同使用了同一個對象。下面看幾個常見的有關字串緩衝池的問題。
到底建立了幾個字串對象
String a = "abc"; String b = "abc"; String c = new String("xyz"); String d = new String("xyz"); String e="ab"+"cd";
這個程式與上邊的程式比較相似,我們分比來看一下:
String a = “abc”;這一句由於緩衝池中沒有abc這個字串對象,所以會建立一個對象;String b = “abc”;由於緩衝池中已經有了abc這個對象,所以不會再建立新的對象;String c = new String(“xyz”);由於沒有xyz這個字串對象,所以會首先建立一個xyz的對象,然後這個字串對象由作為String的構造方法,在記憶體中(不是緩衝池中)又建立了一個新的字串對象,所以一共建立了兩個對象;String d = new String(“xyz”);省略了建立一個對象的過程,所以只建立了一個對象;String e=”ab”+”cd”;由於常量的值在編譯的時候就被確定了。所以這一句等價於String e=”abcd”;建立了一個對象
所以建立的對象的個數分別是:1,0,2,1,1
到底相等不相等
我們在學習java時就知道兩個字串對象相等的判斷要用equal而不能使用==,但是學習了字串緩衝池以後,應該知道為什麼不能用==,什麼情況下==和equal是等價的,首先,必須知道的是,==比較的是兩個對象的記憶體位址是否相等,下面我們就通過幾個程式來看一下:
public static void main(String[] args) { String s1 = "Monday"; String s2 = "Monday"; if (s1 == s2) System.out.println("s1 == s2"); else System.out.println("s1 != s2"); }
輸出結果:s1 == s2
分析:通過上邊的介紹字串緩衝池,我們知道s1和s2都是指向字串緩衝池中的同一個對象,所以記憶體位址是一樣的,所以用==可以判斷兩個字串是否相等。
public static void main(String[] args) { String s1 = "Monday"; String s2 = new String("Monday"); if (s1 == s2) System.out.println("s1 == s2"); else System.out.println("s1 != s2"); if (s1.equals(s2)) System.out.println("s1 equals s2"); else System.out.println("s1 not equals s2"); }
輸出結果:s1 != s2
s1 equals s2
分析:由上邊的分析我們知道,String s2 = new String(“Monday”);這一句話沒有在字串緩衝池中建立新的對象,但是會在記憶體的其他位置建立一個新的對象,所以s1是指向字串緩衝池的,s2是指向記憶體的其他位置,兩者的記憶體位址不同的。
public static void main(String[] args) { String s1 = "Monday"; String s2 = new String("Monday"); s2 = s2.intern(); if (s1 == s2) System.out.println("s1 == s2"); else System.out.println("s1 != s2"); if (s1.equals(s2)) System.out.println("s1 equals s2"); else System.out.println("s1 not equals s2"); }
輸出結果:s1 == s2
s1 equals s2
分析:先來說說intern()這個方法的作用吧,這個方法的作用是返回在字串緩衝池中的對象的引用,所以s2指向的也是字串緩衝池中的地址,和s1是相等的。
public static void main(String[] args) { String Monday = "Monday"; String Mon = "Mon"; String day = "day"; System.out.println(Monday == "Mon" + "day"); System.out.println(Monday == "Mon" + day); }
輸出結果:true
false
分析:第一個為什麼等於true我們已經說過了,因為兩者都是常量所以在編譯階段就已經能確定了,在第二個中,day是一個變數,所以不能提前確定他的值,所以兩者不相等,從這個例子我們可以看出,只有+串連的兩邊都是字串常量時,引用才會指向字串緩衝池,都則都是指向記憶體中的其他地址。
public static void main(String[] args) { String Monday = "Monday"; String Mon = "Mon"; final String day = "day"; System.out.println(Monday == "Mon" + "day"); System.out.println(Monday == "Mon" + day); }
輸出結果:true
true
分析:加上final後day也變成了常量,所以第二句的引用也是指向的字串緩衝池。
附錄
java源碼中對於String a = new String(”abc”);這種構造方法的實現
public String(String original) { this.value = original.value; this.hash = original.hash; }
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
java字串緩衝池分析