Java String類源碼解析


String直接繼承Object

含有一個char[] value,還有一個int hash默認值為0

new String()的構造產生的是一個值為””的字符數組

String(char value[], int offset, int count)當count=0且offset<=value.length時構造一個值為””的字符串。offset>0且offset+count<=value.length時復制該部分子串。其余情況都會拋錯。

字符數據類型是一個采用UTF-16編碼表示Unicode代碼點的代碼單元。大多數的常用Unicode字符使用一個代碼單元就可以表示,而輔助字符需要一對代碼單元表示。而length返回的是UTF-16下的代碼單元的數量,而codePointCount返回的是代碼點的數量。對於大部分人工輸入的字符,這兩者是相等的,會出現length比codePointCount長的通常是某些數學或者機器符號,需要兩個代碼單元來表示一個代碼點。

對於返回char[]的方法,底層調用的是System.arraycopy方法,這也是高效的數組拷貝函數。

getBytes方法會調用StringCoding.encode返回序列化后的byte[]

關於String a == String b的判斷,是指a和b指向內存中的同一個對象,凡是new String初始化的對象,都不會產生a==b的情況,因為他會新開辟一個對象空間,然后復制value的值,僅當b=a初始化時a==b成立。

public static void main(String args[]) {
        String a, b;
        a = "123";
        b = "123";
        System.out.println(a==b);//true
        a = "123";
        b = new String("123");
        System.out.println(a==b);//false
        a = new String("123");
        b = new String("123");
        System.out.println(a==b);//false
        a = "123";
        b = new String(a);
        System.out.println(a==b);//false
        a = new String("123");
        b = a;
        System.out.println(a==b);//true
    }

而a.equals(b)先判斷a == b是否成立,再判斷b是否是String類,然后逐個比較value數組的值是否相等。equalsIgnoreCase在此基礎上忽略大小寫的區別

a.compareTo(b)比較a和b第一個不相等字符的差值,若都相等則比較長度差值。compareToIgnoreCase多一個忽略大小寫的區別。regionMatches(int toffset, String other, int ooffset, int len)則是比較a從toffset開始和other從ooffset開始長度為len的部分是否相等。

startsWith(String prefix, int toffset)字符串從tooffset位置開始和prefix是否相等。endsWith(String suffix)字符串結尾和suffix等長部分是否相等。

hashCode()調用時,若hash值為0且字符串長度不為0,則要計算hash值,方法是value數組化為31進制

indexOf是返回第一個出現的指定值的位置,可以通過fromIndex來指定開始查找的位置,而indexOfSupplementary是忽略大小寫的該方法。lastIndexOf則是從尾部開始查找最后一個。

substring根據指定的位置返回一個新的子字符串,若指定位置不符合原字符串的長度,則拋錯。

a.concat(String str)新建一個字符串內容是a+str並返回,不會修改a原本的值

public static void main(String args[]) {
        String a, b;
        a = "123";
        b = "123";
        a.concat(b);
        System.out.println(a);//123
        System.out.println(a.concat(b));//123123
        a = a.concat(b);
        System.out.println(a);//123123
    }

replace(char oldChar, char newChar)生成一個新的字符串,將原字符串中的oldChar字符全部替換為newChar,不會改變原字符串的值。replaceAll(String regex, String replacement)和前一個方法相比,參數regex是正則表達式,其余相同。

public static void main(String args[]) {
        String a;
        a = "12131";
        a.replace("1", "a");
        System.out.println(a);//12131
        a = a.replace("1", "a");
        System.out.println(a);//a2a3a
    }

split(String regex, int limit)將字符串按照給定的正則表達式分割為字符串組,limit是分割產生的數組最大數量,對於多余部分不做分割全部保留在最后一個字符串中。

public static void main(String args[]) {
        String a;
        a = "1,2,3,4";
        String[] b = a.split(",");
        for(String t : b){
            System.out.print(t + " ");//1 2 3 4
        }
        System.out.println("");
        String[] c = a.split(",", 3);
        for(String t : c){
            System.out.print(t + " ");//1 2 3,4
        }
    }

toCharArray()復制出一個新的char[]而不是直接返回value

trim()生成一個新的字符串,去掉頭部的所有空格

public native String intern()這個方法的作用是在常量池當中尋找是否已經存在該字符串,若已存在則返回該引用,若不存在則在常量池新建。從上面的源碼分析中,我們可以看出String的所有操作都是返回一個新的字符串,對自身是沒有修改的,String被設計為一個不可變的final對象,理由有以下幾點:

1. 字符串常量池的需要。字符串常量池的誕生是為了提升效率和減少內存分配。、因為String的不可變性,常量池很容易被管理和優化。

2. 安全性考慮。正因為使用字符串的場景如此之多,所以設計成不可變可以有效的防止字符串被有意或者無意的篡改。(通過反射或者Unsafe直接操作內存的手段也可以實現對所謂不可變String的修改)。

3. 作為HashMap、HashTable等hash型數據key的必要。因為不可變的設計,jvm底層很容易在緩存String對象的時候緩存其hashcode,這樣在執行效率上會大大提升。

public static void main(String args[]) {
        String a, b;
        a = "123";
        b = new String(a).intern();
        System.out.println(a == b);//true
        a = "12" + "3";
        b = "123";
        System.out.println(a == b);//true
        a = "12" + "3";
        b = new String("123");
        System.out.println(a == b);//false
        a = "12" + "3";
        b = new String("123").intern();
        System.out.println(a == b);//true
        a = new String("123");
        b = a.intern();
        System.out.println(a == b);//false
    }

從上面一段代碼的運行結果我們可以看到,intern()會從常量池尋找指定的字符串,指向同一個常量池對象的時候,a==b就是成立的。這里說明一下最后一個case,首先常量池存在了”123”,然后a獲得的引用是另一個”123”(因為是new String得到的對象),而b得到的是常量池中第一個”123”的引用,所以a!=b。對於字符串相加的操作"12" + "3",操作過后常量池內會有3個字符串,"12"  "3" “123”

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM