Java學習(20) -- 源碼閱讀(String)

一、String以下幾個特性決定它是不可變的

1、`String`是`final`類,不可繼承。
2、字符數組成員變量`value`使用`final`修飾,也就是常量,常量一大好處就是線程安全,所以`String`不需要考慮線程安全問題。
3、通過反射還是可以修改value常量值的,這時候會發現如果字符串是在常量池裏,那麼這個常量池字符串將會被修改成其他值。
4、成員變量`value`字符數組必須獨有,其他程序(不包括String類和反射)不可操作`value`字符數組

二、String 構造器

/**
*創建空的字符串數組
*/
public String() {
     this.value = "".value;
}

//新創建的字符串是參數字符串的副本。不需要,因爲字符串是不可變的。
public String(String original) {
     this.value = original.value;
     this.hash = original.hash;
}
//根據數組創建字符串(方式一)
//傳入一個字符數組,將該數組拷貝一份複製給value,其實這樣做就是爲了保證String不可變性
public String(char value[]) {
    this.value = Arrays.copyOf(value, value.length);
}

//根據數組創建字符串(方式二)
//取得傳入字符數組的部分元素,在第一種情況下,就是多了對傳入的offset count變量判斷是否下標越界
public String(char value[], int offset, int count) {
        if (offset < 0) {
            throw new StringIndexOutOfBoundsException(offset);
        }
        if (count <= 0) {
            if (count < 0) {
                throw new StringIndexOutOfBoundsException(count);
            }
            if (offset <= value.length) {
                this.value = "".value;
                return;
            }
        }
        // Note: offset or count might be near -1>>>1.
        if (offset > value.length - count) {
            throw new StringIndexOutOfBoundsException(offset + count);
        }
        this.value = Arrays.copyOfRange(value, offset, offset+count);
    }

//根據數組創建字符串(方式三)
//bytes:需要轉換成字符串的字節數組

//offset:字節數組的第一個字節的下標

//length:需要轉換成字符串的字節長度=

//charsetName:編碼格式的字符串名稱,如:UTF-8

//charset:編碼格式java.nio.charset.Charset,如:Charset.forName("UTF-8");

public String(byte bytes[], int offset, int length, Charset charset) {
        if (charset == null)
            throw new NullPointerException("charset");
        checkBounds(bytes, offset, length);
        this.value =  StringCoding.decode(charset, bytes, offset, length);
    }

三、String(StringBuffer buffer)和public String(StringBuilder builder)

public String(StringBuffer buffer) {
        synchronized(buffer) {
            this.value = Arrays.copyOf(buffer.getValue(), buffer.length());
        }
    }
public String(StringBuilder builder) {
        this.value = Arrays.copyOf(builder.getValue(), builder.length());
    }

從源碼可知,是複製數組然後賦值

四、String.intern() 這是重點

1、字符串常量池,初始是空的,它是由String類私自維護的。
2、當intern方法調用,如果常量池中存在這個字符串(由equals方法判斷相等的),則返回常量池中的字符串,否則將這個字符串添加到常量池中,並返回一個對這個對象的引用。
其實就是存在則返回,否則添加並返回。
由此可見,對於任意兩個字符串s和t,s.intern() == t.intern() 是 true,s.equals(t) 也是 true。
3、所有的字符串和字符串值的常數表達式都被插入 ,字符串字面量是在 Java™語言規範的3.10.5. String 字面量中定義的,關於字面

char[] value = {'1','a','2','b'};
String str = "1a2b";//常量池中創建
String s = new String(value);//在堆中創建String對象
String intern = s.intern();//從常量池中獲取
System.out.println(str==s);//false
System.out.println(str==intern);//true
System.out.println(s==intern);//false   

五、字符串拼接

 

方式一:
String a = "123"+"456";
//這種方式的拼接在class編譯後變成
String a = "123456";

方式二:
public void appen(String a) {
   String a = a + "124";
}
//這種編譯後在class中是使用StringBuilder的append()拼接
new StringBuilder().append(a).append("124").toString();


//原理可去查看我的語法糖博客

如有疏漏之處,請各位斧正;

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章