String類源碼筆記(一):成員變量和構(gòu)造器

String類表示字符串,所有類似"abc"形式的字符串(或魔法字符串)都被看作是這個類的實(shí)例。String是不可變的院领,當(dāng)一個字符串在常量池中被創(chuàng)建時(shí),他的值就不會被改變够吩。

不可變類指的是其實(shí)例不能被修改的類比然。每個實(shí)例中包含的所有信息都必須在創(chuàng)建該實(shí)例的時(shí)候就提供,并且在對象的整個生命周期內(nèi)固定不變周循。為了使類不可變强法,要遵循下面五條規(guī)則:
1. 不要提供任何會修改對象狀態(tài)的方法万俗。
2. 保證類不會被擴(kuò)展。 一般的做法是讓這個類稱為 final 的饮怯,防止子類化闰歪,破壞該類的不可變行為。
3. 使所有的域都是 final 的蓖墅。
4. 使所有的域都成為私有的库倘。 防止客戶端獲得訪問被域引用的可變對象的權(quán)限,并防止客戶端直接修改這些對象论矾。
5. 確保對于任何可變性組件的互斥訪問于樟。 如果類具有指向可變對象的域,則必須確保該類的客戶端無法獲得指向這些對象的引用拇囊。

public final class String implements java.io.Serializable, Comparable<String>, CharSequence

所在路徑:\java\lang\String.java

String類的成員變量
String類的構(gòu)造器

一、成員變量

為了保證String類是一個不可變類靶橱,String類的成員變量多為私有和不可變的寥袭。

/** 存儲String對象的值 */ 
private final char value[]; 
/** hashcode */ 
private int hash; 
/** serialVersionUID */ 
private static final long serialVersionUID = -6849794470754667710L;
 /** 序列化時(shí)使用,表明需要序列化的部分 */ 
private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0];

其中serialPersistentFields在序列化時(shí)使用:

For class that implements Serializable interface there are 2 ways to define what specific fields get streamed during the serialization:
1关霸、By default all non-static, non-transient fields that implement Serializable are preserved.
2传黄、By definning ObjectStreamField [] serialPersistentFields and explicitly declaring the specific fields saved.
The 'advantage' is that it does what it says in the Javadoc: defines which fields are serialized. Without it, all non-transient non-static fields are serialized. Your choice.

二、構(gòu)造器

JDK8的String類一共有16個構(gòu)造器队寇,其中兩個是@Deprecated膘掰,一個是私有構(gòu)造器,剩下的13個是可以調(diào)用的佳遣。

1识埋、無參構(gòu)造器

無參構(gòu)造器直接將""的value賦值給當(dāng)前類的value。""的value是一個空的char[]零渐,其length為0窒舟。調(diào)用使用了無參構(gòu)造器的String對象的isEmpty()方法會得到true,調(diào)用length()方法會得到0诵盼,判斷其==null會得到false惠豺。

public String() { 
    this.value = "".value; 
}
2、入?yún)镾tring對象

入?yún)镾tring對象時(shí)风宁,構(gòu)造器會對其進(jìn)行直接取值洁墙。

public String(String original) { 
    this.value = original.value; 
    this.hash = original.hash; 
}
3、入?yún)閏har[]

入?yún)樽址當(dāng)?shù)組時(shí)戒财,構(gòu)造器調(diào)用的是Arrays.copyOf()方法热监。

public String(char value[]) { 
    this.value = Arrays.copyOf(value, value.length);
 }

其中Arrays.copyOf()方法是為了將入?yún)⒌淖址蛄猩羁截惖絫his.valuie中,他的源碼為:

public static char[] copyOf(char[] original, int newLength) {
    char[] copy = new char[newLength];
    System.arraycopy(original, 0, copy, 0,
                     Math.min(original.length, newLength));
    return copy;
}

其中System.arraycopy()方法的源碼為:

public static native void arraycopy(Object src,  int  srcPos,
                                    Object dest, int destPos,
                                    int length);

String和char[]的相互轉(zhuǎn)換:
https://www.cnblogs.com/rrttp/p/7922202.html

4固翰、入?yún)閏har[]狼纬,偏移量和有效長度

這個方法支持直接傳入想要生成的String的母串羹呵,通過偏移量和有效長度找出需要賦值給this.value的部分,然后調(diào)用Arrays.copyOfRange()方法進(jìn)行深拷貝疗琉。

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);
}
5冈欢、其他

當(dāng)需要將一個Unicode編碼序列轉(zhuǎn)換為String時(shí),可以使用以下構(gòu)造器:

public String(int[] codePoints, int offset, int count)

參考:https://blog.csdn.net/qq_39477410/article/details/82469104

當(dāng)需要將一個bytes[]轉(zhuǎn)換為String時(shí)盈简,可以使用以下構(gòu)造器:

// 可以傳入JDK支持的字符集名稱
public String(byte bytes[], int offset, int length, String charsetName)
    throws UnsupportedEncodingException

// 也可以傳入自定義的解碼字符集
public String(byte bytes[], int offset, int length, Charset charset)

此外凑耻,還有一些將上述構(gòu)造器進(jìn)一步封裝的構(gòu)造器,其本質(zhì)都是簡化入?yún)⒛汀A硗庀愫疲琒tring類的構(gòu)造器同樣支持傳入StringBuffer和StringBuilder。如果傳入的是StringBuffer臼勉,構(gòu)造器會為其加鎖邻吭。如果傳入的是StringBuilder則不會加鎖。

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

事實(shí)上宴霸,StringBuffer和StringBuilder的toString()方法調(diào)用的也是String類的構(gòu)造器囱晴,他們最終的底層實(shí)現(xiàn)都是Arrays.copyOf()。

// StringBuffer的toString()方法
@Override
public synchronized String toString() {
    if (toStringCache == null) {
        toStringCache = Arrays.copyOfRange(value, 0, count);
    }
    return new String(toStringCache, true);
}

// StringBuilder的toString()方法
@Override
public String toString() {
    // Create a copy, don't share the array
    return new String(value, 0, count);
}

最后瓢谢,String類還提供了一個保護(hù)類型的構(gòu)造方法畸写。該方法相比入?yún)閏har[]的構(gòu)造器多了一個share參數(shù),這個參數(shù)并沒有實(shí)際作用氓扛,只是用來和其他構(gòu)造器進(jìn)行區(qū)分枯芬。當(dāng)String類內(nèi)部調(diào)用該構(gòu)造器時(shí):

  • 直接賦值而不是使用Arrays.copyOf()方法可以獲得更高的效率;
  • 同時(shí)共享字符串?dāng)?shù)組的方式也可以節(jié)省內(nèi)存采郎。

該構(gòu)造器不能對外暴露的原因是需要保持String類的不可變性千所。

/*
* Package private constructor which shares value array for speed.
* this constructor is always expected to be called with share==true.
* a separate constructor is needed because we already have a public
* String(char[]) constructor that makes a copy of the given char[].
*/
String(char[] value, boolean share) {
    // assert share : "unshared not supported";
    this.value = value;
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市蒜埋,隨后出現(xiàn)的幾起案子真慢,更是在濱河造成了極大的恐慌,老刑警劉巖理茎,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件黑界,死亡現(xiàn)場離奇詭異,居然都是意外死亡皂林,警方通過查閱死者的電腦和手機(jī)朗鸠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來础倍,“玉大人烛占,你說我怎么就攤上這事。” “怎么了忆家?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵犹菇,是天一觀的道長。 經(jīng)常有香客問我芽卿,道長揭芍,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任卸例,我火速辦了婚禮称杨,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘筷转。我一直安慰自己姑原,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布呜舒。 她就那樣靜靜地躺著锭汛,像睡著了一般。 火紅的嫁衣襯著肌膚如雪袭蝗。 梳的紋絲不亂的頭發(fā)上店乐,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天,我揣著相機(jī)與錄音呻袭,去河邊找鬼。 笑死腺兴,一個胖子當(dāng)著我的面吹牛左电,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播页响,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼篓足,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了闰蚕?” 一聲冷哼從身側(cè)響起栈拖,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎没陡,沒想到半個月后涩哟,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡盼玄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年贴彼,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片埃儿。...
    茶點(diǎn)故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡器仗,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情精钮,我是刑警寧澤威鹿,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站轨香,受9級特大地震影響忽你,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜弹沽,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一檀夹、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧策橘,春花似錦炸渡、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至沛婴,卻和暖如春吼畏,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背嘁灯。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工泻蚊, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人丑婿。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓性雄,卻偏偏與公主長得像,于是被迫代替她去往敵國和親羹奉。 傳聞我的和親對象是個殘疾皇子秒旋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評論 2 350

推薦閱讀更多精彩內(nèi)容