關於java字符串的內存問題

入Java字符串
 
 
Java字符串類(java.lang.String)是Java中使用最多的類,也是最爲特殊的一個類,很多時候,我們對它既熟悉又陌生。
 
一、從根本上認識java.lang.String類和String池
 
首先,我建議先看看String類的源碼實現,這是從本質上認識String類的根本出發點。從中可以看到:
1、String類是final的,不可被繼承。public final class String。
2、String類是的本質是字符數組char[], 並且其值不可改變。private final char value[];
然後打開String類的API文檔,可以發現:
3、String類對象有個特殊的創建的方式,就是直接指定比如String x = "abc","abc"就表示一個字符串對象。而x是"abc"對象的地址,也叫做"abc"對象的引用。
4、String對象可以通過“+”串聯。串聯後會生成新的字符串。也可以通過concat()來串聯,這個後面會講述。
6、Java運行時會維護一個String Pool(String池),JavaDoc翻譯很模糊“字符串緩衝區”。String池用來存放運行時中產生的各種字符串,並且池中的字符串的內容不重複。而一般對象不存在這個緩衝池,並且創建的對象僅僅存在於方法的堆棧區。下面是個系統內存示意圖:
 
5、創建字符串的方式很多,歸納起來有三類:
其一,使用new關鍵字創建字符串,比如String s1 = new String("abc");
其二,直接指定。比如String s2 = "abc";
其三,使用串聯生成新的字符串。比如String s3 = "ab" + "c";
 
二、String對象的創建
 
String對象的創建也很講究,關鍵是要明白其原理。
原理1:當使用任何方式來創建一個字符串對象s時,Java運行時(運行中JVM)會拿着這個X在String池中找是否存在內容相同的字符串對象,如果不存在,則在池中創建一個字符串s,否則,不在池中添加。
 
原理2:Java中,只要使用new關鍵字來創建對象,則一定會(在堆區或棧區)創建一個新的對象。
 
原理3:使用直接指定或者使用純字符串串聯來創建String對象,則僅僅會檢查維護String池中的字符串,池中沒有就在池中創建一個,有則罷了!但絕不會在堆棧區再去創建該String對象。
 
原理4:使用包含變量的表達式來創建String對象,則不僅會檢查維護String池,而且還會在堆棧區創建一個String對象。
 
另外,String的intern()方法是一個本地方法,定義爲public native String intern(); intern()方法的價值在於讓開發者能將注意力集中到String池上。當調用 intern 方法時,如果池已經包含一個等於此 String 對象的字符串(該對象由 equals(Object) 方法確定),則返回池中的字符串。否則,將此 String 對象添加到池中,並且返回此 String 對象的引用。
 
 
三、認識trim()、intern()和concat()、“+”。
 
三、認識空格、空串、null
 
下面看個例子:
/** 
* Created by IntelliJ IDEA.<br> 
* <b>User</b>: leizhimin<br> 
* <b>Date</b>: 2008-6-2 22:14:16<br> 
* <b>Note</b>: Please add comment here! 
*/
 
public class StringTest { 
    public static void main(String args[]) { 
        //在池中和堆中分別創建String對象"abc",s1指向堆中對象 
        String s1 = new String("abc"); 
        //s2直接指向池中對象"abc" 
        String s2 = "abc"
        //在堆中新創建"abc"對象,s3指向該對象 
        String s3 = new String("abc"); 
        //在池中創建對象"ab" 和 "c",並且s4指向池中對象"abc" 
        String s4 = "ab" + "c"
        //c指向池中對象"c" 
        String c = "c"
        //在堆中創建新的對象"abc",並且s5指向該對象 
        String s5 = "ab" + c; 

        String s6 = "ab".concat("c"); 
        String s7 = "ab".concat(c); 

        System.out.println("------------實串-----------"); 
        System.out.println(s1 == s2); //false 
        System.out.println(s1 == s3); //false 
        System.out.println(s2 == s3); //false 
        System.out.println(s2 == s4); //true 
        System.out.println(s2 == s5); //false 
        System.out.println(s2 == s6); //false 
        System.out.println(s2 == s7); //false 

        String b1 = new String(""); 
        String b2 = ""; 
        String b3 = new String(""); 
        String b4 = "".intern(); 
        String b5 = "" + ""; 
        String b6 = "".concat(""); 
        String b7 = "  ".trim(); 
        String b8 = "  "
        String b9 = "    ".trim(); 

        System.out.println("------------空串-----------"); 
        System.out.println(b1 == b2);  //false 
        System.out.println(b1 == b3);  //false 
        System.out.println(b2 == b3);  //false 
        System.out.println(b2 == b4);  //true 
        System.out.println(b2 == b5);  //true* 
        System.out.println(b2 == b6);  //true* 
        System.out.println(b2 == b7);  //false* 
        System.out.println("-----a----"); 
        System.out.println(b2.equals(b7));  //true 
        System.out.println(b7 == b8);  //false 
        System.out.println(b7 == b9);  //false 
        System.out.println(b7.equals(b9)); //true 
        System.out.println(b9 == null);//false 

        System.out.println("b8.trim():"); 
        for (byte b : b8.getBytes()) { 
            System.out.print(">>>" + (int) b + " "); 
        } 
        System.out.println("\nb8.trim():"); 
        for (byte b : b8.trim().getBytes()) { 
            System.out.print(">>>" + (int) b + " "); 
        } 
        System.out.println("\nb9.trim():"); 
        for (byte b : b9.trim().getBytes()) { 
            System.out.print(">>>" + (int) b + " "); 
        } 
    } 
}
 
四、String的常見用法
 
1、字符串重編碼
這個問題說來比較簡單,轉碼就一行搞定,不信你看看,但究竟爲什麼要轉碼,是個很深奧的問題,看例子:
import java.io.UnsupportedEncodingException; 

/** 
* 字符串轉碼測試 

* @author leizhimin 2009-7-17 10:50:06 
*/
 
public class TestEncoding { 
        public static void main(String[] args) throws UnsupportedEncodingException { 
                System.out.println("轉碼前,輸出Java系統屬性如下:"); 
                System.out.println("user.country:" + System.getProperty("user.country")); 
                System.out.println("user.language:" + System.getProperty("user.language")); 
                System.out.println("sun.jnu.encoding:" + System.getProperty("sun.jnu.encoding")); 
                System.out.println("file.encoding:" + System.getProperty("file.encoding")); 

                System.out.println("---------------"); 
                String s = "熔岩博客"
                String s1 = new String(s.getBytes(), "UTF-8"); 
                String s2 = new String(s.getBytes("UTF-8"), "UTF-8"); 
                String s3 = new String(s.getBytes("UTF-8")); 
                String s4 = new String(s.getBytes("UTF-8"), "GBK"); 
                String s5 = new String(s.getBytes("GBK")); 
                String s6 = new String(s.getBytes("GBK"), "GBK"); 
                System.out.println(s1); 
                System.out.println(s2); 
                System.out.println(s3); 
                System.out.println(s4); 
                System.out.println(s5); 
                System.out.println(s6); 
        } 
}
 
輸出結果:
轉碼前,輸出Java系統屬性如下: 
user.country:CN 
user.language:zh 
sun.jnu.encoding:GBK 
file.encoding:UTF-8 
--------------- 
熔岩博客 
熔岩博客 
熔岩博客 
鐔斿博鍗氬 
���Ҳ��� 
熔岩博客 

Process finished with exit code 0
 
得出一結論:
a、轉一個碼,又用該碼來構建一個字符串,是絕對不會出現亂碼的,----你相當於沒轉。
b、轉碼與否,與字符串本身編碼有關,字符串本身的編碼與誰有關?----文件編碼,或者你的IDE設置的編碼有關。
在此,我用的IDEA開發工具,默認是UTF-8編碼,但操作系統使用的是GBK,但沒有問題,我只要按照UTF-8來讀取我的字符串就不會有亂碼。但是文件已經是UTF-8了,你非要轉爲GBK,不亂纔怪!那有什麼辦法呢?在Windows下,用記事本或者Editplus打開後另存爲(並修改編碼方式即可)。
 
至於已經要從UFT-8轉換爲GBK,這就要靠內碼轉換工具了,是個比較複雜的問題,如果有誰想研究可以告訴我,一塊研究研究。
 
2、字符比較
不就是個匹配關係嗎?String類的API有一些可以做比較,如果不行,可以尋求正則表達式來解決。
 
3、獲取某個字符
獲取一個字符序列toCharArray() ,然後就隨便玩去吧,中文就亂了。
4、字符串的截取
substring()
 
5、字符串的替換與查找
 
6、開始結束判斷
startsWith()/endWith()
 
7、字符串的排序比較
compareTo(String anotherString) 
          按字典順序比較兩個字符串。 
compareToIgnoreCase(String str) 
          不考慮大小寫,按字典順序比較兩個字符串。
 
8、字符串的equals()和hashCode()
已經實現了好了,直接調用,不用重寫
 
9、字符串的類型轉化
太多了,String.valueOf()系列很多。
類似的Long.parseLong(String s) 
10、字符串的複製
 
11、大小寫轉換
 
發佈了59 篇原創文章 · 獲贊 9 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章