Java面試題String面試題

String 對(duì)象是我們使用最頻繁的一個(gè)對(duì)象類(lèi)型顷编,但它的性能問(wèn)題卻是最容易被忽略的戚炫。String 對(duì)象作為 Java 語(yǔ)言中重要的數(shù)據(jù)類(lèi)型,是內(nèi)存中占據(jù)空間最大的一個(gè)對(duì)象媳纬。高效地使用字符串双肤,可以提升系統(tǒng)的整體性能。

接下來(lái)我們就從 String 對(duì)象的實(shí)現(xiàn)钮惠、特性以及實(shí)際使用中的優(yōu)化這三個(gè)方面入手茅糜,深入了解。

在開(kāi)始之前素挽,我想先問(wèn)你一個(gè)小問(wèn)題蔑赘,也是我在招聘時(shí),經(jīng)常會(huì)問(wèn)到面試者的一道題预明。雖是老生常談了缩赛,但錯(cuò)誤率依然很高,當(dāng)然也有一些面試者答對(duì)了撰糠,但能解釋清楚答案背后原理的人少之又少酥馍。問(wèn)題如下:

通過(guò)三種不同的方式創(chuàng)建了三個(gè)對(duì)象,再依次兩兩匹配阅酪,每組被匹配的兩個(gè)對(duì)象是否相等旨袒?代碼如下:
String str1= "abc";
String str2= new String("abc");
String str3= str2.intern();
assertSame(str1==str2);
assertSame(str2==str3);
assertSame(str1==str3)</pre>

你可以先想想答案,以及這樣回答的原因术辐。希望通過(guò)今天的學(xué)習(xí)砚尽,你能拿到滿分。

String 對(duì)象是如何實(shí)現(xiàn)的辉词?

在 Java 語(yǔ)言中尉辑,Sun 公司的工程師們對(duì) String 對(duì)象做了大量的優(yōu)化,來(lái)節(jié)約內(nèi)存空間较屿,提升 String 對(duì)象在系統(tǒng)中的性能隧魄。一起來(lái)看看優(yōu)化過(guò)程,如下圖所示:

image.jpeg

1. 在 Java6 以及之前的版本中隘蝎,String 對(duì)象是對(duì) char 數(shù)組進(jìn)行了封裝實(shí)現(xiàn)的對(duì)象购啄,主要有四個(gè)成員變量:char 數(shù)組、偏移量 offset嘱么、字符數(shù)量 count狮含、哈希值 hash。

String 對(duì)象是通過(guò) offset 和 count 兩個(gè)屬性來(lái)定位 char[] 數(shù)組,獲取字符串几迄。這么做可以高效蔚龙、快速地共享數(shù)組對(duì)象,同時(shí)節(jié)省內(nèi)存空間映胁,但這種方式很有可能會(huì)導(dǎo)致內(nèi)存泄漏木羹。

2. 從 Java7 版本開(kāi)始到 Java8 版本,Java 對(duì) String 類(lèi)做了一些改變解孙。String 類(lèi)中不再有 offset 和 count 兩個(gè)變量了坑填。這樣的好處是 String 對(duì)象占用的內(nèi)存稍微少了些,同時(shí)弛姜,String.substring 方法也不再共享 char[]脐瑰,從而解決了使用該方法可能導(dǎo)致的內(nèi)存泄漏問(wèn)題。

3. 從 Java9 版本開(kāi)始廷臼,工程師將 char[] 字段改為了 byte[] 字段苍在,又維護(hù)了一個(gè)新的屬性 coder,它是一個(gè)編碼格式的標(biāo)識(shí)荠商。

工程師為什么這樣修改呢忌穿?

我們知道一個(gè) char 字符占 16 位,2 個(gè)字節(jié)结啼。這個(gè)情況下掠剑,存儲(chǔ)單字節(jié)編碼內(nèi)的字符(占一個(gè)字節(jié)的字符)就顯得非常浪費(fèi)。JDK1.9 的 String 類(lèi)為了節(jié)約內(nèi)存空間郊愧,于是使用了占 8 位朴译,1 個(gè)字節(jié)的 byte 數(shù)組來(lái)存放字符串。

而新屬性 coder 的作用是属铁,在計(jì)算字符串長(zhǎng)度或者使用 indexOf()函數(shù)時(shí)眠寿,我們需要根據(jù)這個(gè)字段,判斷如何計(jì)算字符串長(zhǎng)度焦蘑。coder 屬性默認(rèn)有 0 和 1 兩個(gè)值盯拱,0 代表 Latin-1(單字節(jié)編碼),1 代表 UTF-16例嘱。如果 String 判斷字符串只包含了 Latin-1狡逢,則 coder 屬性值為 0,反之則為 1拼卵。

String 對(duì)象的不可變性

了解了 String 對(duì)象的實(shí)現(xiàn)后奢浑,你有沒(méi)有發(fā)現(xiàn)在實(shí)現(xiàn)代碼中 String 類(lèi)被 final 關(guān)鍵字修飾了,而且變量 char 數(shù)組也被 final 修飾了腋腮。

我們知道類(lèi)被 final 修飾代表該類(lèi)不可繼承雀彼,而 char[] 被 final+private 修飾壤蚜,代表了 String 對(duì)象不可被更改。Java 實(shí)現(xiàn)的這個(gè)特性叫作 String 對(duì)象的不可變性徊哑,即 String 對(duì)象一旦創(chuàng)建成功袜刷,就不能再對(duì)它進(jìn)行改變。

Java 這樣做的好處在哪里呢莺丑?

第一著蟹,保證 String 對(duì)象的安全性。假設(shè) String 對(duì)象是可變的窒盐,那么 String 對(duì)象將可能被惡意修改。

第二钢拧,保證 hash 屬性值不會(huì)頻繁變更蟹漓,確保了唯一性,使得類(lèi)似 HashMap 容器才能實(shí)現(xiàn)相應(yīng)的 key-value 緩存功能源内。

第三葡粒,可以實(shí)現(xiàn)字符串常量池。在 Java 中膜钓,通常有兩種創(chuàng)建字符串對(duì)象的方式嗽交,一種是通過(guò)字符串常量的方式創(chuàng)建,如 String str=“abc”颂斜;另一種是字符串變量通過(guò) new 形式的創(chuàng)建夫壁,如 String str = new String(“abc”)。

當(dāng)代碼中使用第一種方式創(chuàng)建字符串對(duì)象時(shí)沃疮,JVM 首先會(huì)檢查該對(duì)象是否在字符串常量池中盒让,如果在,就返回該對(duì)象引用司蔬,否則新的字符串將在常量池中被創(chuàng)建邑茄。這種方式可以減少同一個(gè)值的字符串對(duì)象的重復(fù)創(chuàng)建,節(jié)約內(nèi)存俊啼。

String str = new String(“abc”) 這種方式肺缕,首先在編譯類(lèi)文件時(shí),"abc"常量字符串將會(huì)放入到常量結(jié)構(gòu)中授帕,在類(lèi)加載時(shí)同木,“abc"將會(huì)在常量池中創(chuàng)建;其次跛十,在調(diào)用 new 時(shí)泉手,JVM 命令將會(huì)調(diào)用 String 的構(gòu)造函數(shù),同時(shí)引用常量池中的"abc” 字符串偶器,在堆內(nèi)存中創(chuàng)建一個(gè) String 對(duì)象斩萌;最后缝裤,str 將引用 String 對(duì)象。

這里附上一個(gè)你可能會(huì)想到的經(jīng)典反例颊郎。

平常編程時(shí)憋飞,對(duì)一個(gè) String 對(duì)象 str 賦值“hello”,然后又讓 str 值為“world”姆吭,這個(gè)時(shí)候 str 的值變成了“world”榛做。那么 str 值確實(shí)改變了,為什么我還說(shuō) String 對(duì)象不可變呢内狸?

首先检眯,我來(lái)解釋下什么是對(duì)象和對(duì)象引用。Java 初學(xué)者往往對(duì)此存在誤區(qū)昆淡,特別是一些從 PHP 轉(zhuǎn) Java 的同學(xué)锰瘸。在 Java 中要比較兩個(gè)對(duì)象是否相等,往往是用 ==昂灵,而要判斷兩個(gè)對(duì)象的值是否相等避凝,則需要用 equals 方法來(lái)判斷。

這是因?yàn)?str 只是 String 對(duì)象的引用眨补,并不是對(duì)象本身管削。對(duì)象在內(nèi)存中是一塊內(nèi)存地址,str 則是一個(gè)指向該內(nèi)存地址的引用撑螺。所以在剛剛我們說(shuō)的這個(gè)例子中含思,第一次賦值的時(shí)候,創(chuàng)建了一個(gè)“hello”對(duì)象甘晤,str 引用指向“hello”地址茸俭;第二次賦值的時(shí)候,又重新創(chuàng)建了一個(gè)對(duì)象“world”安皱,str 引用指向了“world”调鬓,但“hello”對(duì)象依然存在于內(nèi)存中。

也就是說(shuō) str 并不是對(duì)象酌伊,而只是一個(gè)對(duì)象引用腾窝。真正的對(duì)象依然還在內(nèi)存中,沒(méi)有被改變居砖。

String 對(duì)象的優(yōu)化

了解了 String 對(duì)象的實(shí)現(xiàn)原理和特性虹脯,接下來(lái)我們就結(jié)合實(shí)際場(chǎng)景,看看如何優(yōu)化 String 對(duì)象的使用奏候,優(yōu)化的過(guò)程中又有哪些需要注意的地方循集。

1. 如何構(gòu)建超大字符串?

編程過(guò)程中蔗草,字符串的拼接很常見(jiàn)咒彤。前面我講過(guò) String 對(duì)象是不可變的疆柔,如果我們使用 String 對(duì)象相加,拼接我們想要的字符串镶柱,是不是就會(huì)產(chǎn)生多個(gè)對(duì)象呢旷档?例如以下代碼:
String str= "ab" + "cd" + "ef";

分析代碼可知:首先會(huì)生成 ab 對(duì)象,再生成 abcd 對(duì)象歇拆,最后生成 abcdef 對(duì)象鞋屈,從理論上來(lái)說(shuō),這段代碼是低效的故觅。
但實(shí)際運(yùn)行中厂庇,我們發(fā)現(xiàn)只有一個(gè)對(duì)象生成,這是為什么呢输吏?難道我們的理論判斷錯(cuò)了权旷?我們?cè)賮?lái)看編譯后的代碼,你會(huì)發(fā)現(xiàn)編譯器自動(dòng)優(yōu)化了這行代碼评也,如下:
String str= "abcdef";

上面我介紹的是字符串常量的累計(jì)炼杖,我們?cè)賮?lái)看看字符串變量的累計(jì)又是怎樣的呢灭返?

String str = "abcdef";

for(int i=0; i<1000; i++) {
str = str + i;
}
上面的代碼編譯后盗迟,你可以看到編譯器同樣對(duì)這段代碼進(jìn)行了優(yōu)化。不難發(fā)現(xiàn)熙含,Java 在進(jìn)行字符串的拼接時(shí)罚缕,偏向使用 StringBuilder,這樣可以提高程序的效率怎静。

String str = "abcdef";

for(int i=0; i<1000; i++) {
str = (new StringBuilder(String.valueOf(str))).append(i).toString();
}</pre>

綜上已知:即使使用 + 號(hào)作為字符串的拼接邮弹,也一樣可以被編譯器優(yōu)化成 StringBuilder 的方式。但再細(xì)致些蚓聘,你會(huì)發(fā)現(xiàn)在編譯器優(yōu)化的代碼中腌乡,每次循環(huán)都會(huì)生成一個(gè)新的 StringBuilder 實(shí)例,同樣也會(huì)降低系統(tǒng)的性能夜牡。

所以平時(shí)做字符串拼接的時(shí)候与纽,我建議你還是要顯示地使用 String Builder 來(lái)提升系統(tǒng)性能。

如果在多線程編程中塘装,String 對(duì)象的拼接涉及到線程安全急迂,你可以使用 StringBuffer。但是要注意蹦肴,由于 StringBuffer 是線程安全的僚碎,涉及到鎖競(jìng)爭(zhēng),所以從性能上來(lái)說(shuō)阴幌,要比 StringBuilder 差一些勺阐。

2. 如何使用 String.intern 節(jié)省內(nèi)存卷中?

講完了構(gòu)建字符串,我們?cè)賮?lái)討論下 String 對(duì)象的存儲(chǔ)問(wèn)題皆看。先看一個(gè)案例仓坞。

Twitter 每次發(fā)布消息狀態(tài)的時(shí)候,都會(huì)產(chǎn)生一個(gè)地址信息腰吟,以當(dāng)時(shí) Twitter 用戶的規(guī)模預(yù)估无埃,服務(wù)器需要 32G 的內(nèi)存來(lái)存儲(chǔ)地址信息。
public class Location {
private String city;
private String region;
private String countryCode;
private double longitude;
private double latitude;
} </pre>

考慮到其中有很多用戶在地址信息上是有重合的毛雇,比如嫉称,國(guó)家、省份灵疮、城市等织阅,這時(shí)就可以將這部分信息單獨(dú)列出一個(gè)類(lèi),以減少重復(fù)震捣,代碼如下:

public class SharedLocation {

private String city;
private String region;
private String countryCode;
}

public class Location {

private SharedLocation sharedLocation;
double longitude;
double latitude;
}

通過(guò)優(yōu)化荔棉,數(shù)據(jù)存儲(chǔ)大小減到了 20G 左右。但對(duì)于內(nèi)存存儲(chǔ)這個(gè)數(shù)據(jù)來(lái)說(shuō)蒿赢,依然很大润樱,怎么辦呢?

這個(gè)案例來(lái)自一位 Twitter 工程師在 QCon 全球軟件開(kāi)發(fā)大會(huì)上的演講羡棵,他們想到的解決方法壹若,就是使用 String.intern 來(lái)節(jié)省內(nèi)存空間,從而優(yōu)化 String 對(duì)象的存儲(chǔ)皂冰。

具體做法就是店展,在每次賦值的時(shí)候使用 String 的 intern 方法,如果常量池中有相同值秃流,就會(huì)重復(fù)使用該對(duì)象赂蕴,返回對(duì)象引用,這樣一開(kāi)始的對(duì)象就可以被回收掉舶胀。這種方式可以使重復(fù)性非常高的地址信息存儲(chǔ)大小從 20G 降到幾百兆概说。

SharedLocation sharedLocation = new SharedLocation();

sharedLocation.setCity(messageInfo.getCity().intern()); sharedLocation.setCountryCode(messageInfo.getRegion().intern());
sharedLocation.setRegion(messageInfo.getCountryCode().intern());

Location location = new Location();
location.set(sharedLocation);
location.set(messageInfo.getLongitude());
location.set(messageInfo.getLatitude());</pre>

為了更好地理解,我們?cè)賮?lái)通過(guò)一個(gè)簡(jiǎn)單的例子峻贮,回顧下其中的原理:

String a =new String("abc").intern();
String b = new String("abc").intern();

if(a==b) {
System.out.print("a==b");
}

輸出結(jié)果:

a==b
在字符串常量中席怪,默認(rèn)會(huì)將對(duì)象放入常量池;在字符串變量中纤控,對(duì)象是會(huì)創(chuàng)建在堆內(nèi)存中挂捻,同時(shí)也會(huì)在常量池中創(chuàng)建一個(gè)字符串對(duì)象,復(fù)制到堆內(nèi)存對(duì)象中船万,并返回堆內(nèi)存對(duì)象引用刻撒。

如果調(diào)用 intern 方法骨田,會(huì)去查看字符串常量池中是否有等于該對(duì)象的字符串,如果沒(méi)有声怔,就在常量池中新增該對(duì)象态贤,并返回該對(duì)象引用;如果有醋火,就返回常量池中的字符串引用悠汽。堆內(nèi)存中原有的對(duì)象由于沒(méi)有引用指向它,將會(huì)通過(guò)垃圾回收器回收芥驳。

了解了原理柿冲,我們?cè)僖黄鹂纯瓷线叺睦印?/p>

在一開(kāi)始創(chuàng)建 a 變量時(shí),會(huì)在堆內(nèi)存中創(chuàng)建一個(gè)對(duì)象兆旬,同時(shí)會(huì)在加載類(lèi)時(shí)假抄,在常量池中創(chuàng)建一個(gè)字符串對(duì)象,在調(diào)用 intern 方法之后丽猬,會(huì)去常量池中查找是否有等于該字符串的對(duì)象宿饱,有就返回引用。

在創(chuàng)建 b 字符串變量時(shí)脚祟,也會(huì)在堆中創(chuàng)建一個(gè)對(duì)象谬以,此時(shí)常量池中有該字符串對(duì)象,就不再創(chuàng)建愚铡。調(diào)用 intern 方法則會(huì)去常量池中判斷是否有等于該字符串的對(duì)象蛉签,發(fā)現(xiàn)有等于"abc"字符串的對(duì)象胡陪,就直接返回引用沥寥。而在堆內(nèi)存中的對(duì)象,由于沒(méi)有引用指向它柠座,將會(huì)被垃圾回收邑雅。所以 a 和 b 引用的是同一個(gè)對(duì)象。

下面我用一張圖來(lái)總結(jié)下 String 字符串的創(chuàng)建分配內(nèi)存地址情況:

使用 intern 方法需要注意的一點(diǎn)是妈经,一定要結(jié)合實(shí)際場(chǎng)景淮野。因?yàn)槌A砍氐膶?shí)現(xiàn)是類(lèi)似于一個(gè) HashTable 的實(shí)現(xiàn)方式,HashTable 存儲(chǔ)的數(shù)據(jù)越大吹泡,遍歷的時(shí)間復(fù)雜度就會(huì)增加骤星。如果數(shù)據(jù)過(guò)大,會(huì)增加整個(gè)字符串常量池的負(fù)擔(dān)爆哑。

3. 如何使用字符串的分割方法洞难?

最后我想跟你聊聊字符串的分割,這種方法在編碼中也很最常見(jiàn)揭朝。Split() 方法使用了正則表達(dá)式實(shí)現(xiàn)了其強(qiáng)大的分割功能队贱,而正則表達(dá)式的性能是非常不穩(wěn)定的色冀,使用不恰當(dāng)會(huì)引起回溯問(wèn)題,很可能導(dǎo)致 CPU 居高不下柱嫌。

所以我們應(yīng)該慎重使用 Split() 方法锋恬,我們可以用 String.indexOf() 方法代替 Split() 方法完成字符串的分割。如果實(shí)在無(wú)法滿足需求编丘,你就在使用 Split() 方法時(shí)与学,對(duì)回溯問(wèn)題加以重視就可以了。

總結(jié)

這一講中嘉抓,我們認(rèn)識(shí)到做好 String 字符串性能優(yōu)化癣防,可以提高系統(tǒng)的整體性能。在這個(gè)理論基礎(chǔ)上掌眠,Java 版本在迭代中通過(guò)不斷地更改成員變量蕾盯,節(jié)約內(nèi)存空間,對(duì) String 對(duì)象進(jìn)行優(yōu)化蓝丙。

我們還特別提到了 String 對(duì)象的不可變性级遭,正是這個(gè)特性實(shí)現(xiàn)了字符串常量池,通過(guò)減少同一個(gè)值的字符串對(duì)象的重復(fù)創(chuàng)建渺尘,進(jìn)一步節(jié)約內(nèi)存挫鸽。

但也是因?yàn)檫@個(gè)特性,我們?cè)谧鲩L(zhǎng)字符串拼接時(shí)鸥跟,需要顯示使用 StringBuilder丢郊,以提高字符串的拼接性能。最后医咨,在優(yōu)化方面枫匾,我們還可以使用 intern 方法,讓變量字符串對(duì)象重復(fù)使用常量池中相同值的對(duì)象拟淮,進(jìn)而節(jié)約內(nèi)存干茉。

最后再分享一個(gè)個(gè)人觀點(diǎn)。那就是千里之堤很泊,潰于蟻穴角虫。日常編程中,我們往往可能就是對(duì)一個(gè)小小的字符串了解不夠深入委造,使用不夠恰當(dāng)戳鹅,從而引發(fā)線上事故。

比如昏兆,在我之前的工作經(jīng)歷中枫虏,就曾因?yàn)槭褂谜齽t表達(dá)式對(duì)字符串進(jìn)行匹配,導(dǎo)致并發(fā)瓶頸,這里也可以將其歸納為字符串使用的性能問(wèn)題模软。

思考題

通過(guò)今天的學(xué)習(xí)伟骨,你知道文章開(kāi)頭那道面試題的答案了嗎?背后的原理是什么燃异?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末携狭,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子回俐,更是在濱河造成了極大的恐慌逛腿,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,884評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件仅颇,死亡現(xiàn)場(chǎng)離奇詭異单默,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)忘瓦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,347評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)搁廓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人耕皮,你說(shuō)我怎么就攤上這事境蜕。” “怎么了凌停?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,435評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵粱年,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我罚拟,道長(zhǎng)台诗,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,509評(píng)論 1 284
  • 正文 為了忘掉前任赐俗,我火速辦了婚禮拉队,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘秃励。我一直安慰自己氏仗,他們只是感情好吉捶,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,611評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布夺鲜。 她就那樣靜靜地躺著,像睡著了一般呐舔。 火紅的嫁衣襯著肌膚如雪币励。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,837評(píng)論 1 290
  • 那天珊拼,我揣著相機(jī)與錄音食呻,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛仅胞,可吹牛的內(nèi)容都是我干的每辟。 我是一名探鬼主播,決...
    沈念sama閱讀 38,987評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼干旧,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼渠欺!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起椎眯,我...
    開(kāi)封第一講書(shū)人閱讀 37,730評(píng)論 0 267
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤挠将,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后编整,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體舔稀,經(jīng)...
    沈念sama閱讀 44,194評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,525評(píng)論 2 327
  • 正文 我和宋清朗相戀三年掌测,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了内贮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,664評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡汞斧,死狀恐怖贺归,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情断箫,我是刑警寧澤拂酣,帶...
    沈念sama閱讀 34,334評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站仲义,受9級(jí)特大地震影響婶熬,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜埃撵,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,944評(píng)論 3 313
  • 文/蒙蒙 一赵颅、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧暂刘,春花似錦饺谬、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,764評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至森缠,卻和暖如春拔鹰,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背贵涵。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,997評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工列肢, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留恰画,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,389評(píng)論 2 360
  • 正文 我出身青樓瓷马,卻偏偏與公主長(zhǎng)得像拴还,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子欧聘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,554評(píng)論 2 349

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