歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Java字符串緩沖池分析

Java字符串緩沖池分析

日期:2017/3/1 9:27:39   编辑:Linux編程

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;
    } 

Copyright © Linux教程網 All Rights Reserved