Map知識(HashMap弧满、TreeMap、ConcurrentHashMAp此熬、HashTable)

文章單純記錄學(xué)習(xí)庭呜,答案不一定正確,大多從網(wǎng)上查閱犀忱,有錯誤望指正


一募谎、HashMap底層數(shù)據(jù)結(jié)構(gòu)以及擴容

HashMap的底層實現(xiàn):JDK1.7是數(shù)組+鏈表;JDK1.8是數(shù)組+鏈表/紅黑樹

1. 擴容的條件:答:JDK1.7版:當(dāng)要添加新Entry對象時發(fā)現(xiàn)(1)size達(dá)到threshold(閾值)(2)table[index]!=null時阴汇,兩個條件同時滿足會擴容

JDK1.8版:當(dāng)要添加新Entry對象時發(fā)現(xiàn)(1)size達(dá)到threshold(閾值)(2)當(dāng)table[index]下的結(jié)點個數(shù)達(dá)到8個但是table.length又沒有達(dá)到64数冬。兩種情況滿足其一都會導(dǎo)致數(shù)組擴容

而且數(shù)組一旦擴容,不管哪個版本搀庶,都會導(dǎo)致所有映射關(guān)系重新調(diào)整存儲位置拐纱。

擴容:

2. put(key,value) -JDK1.7

(1)當(dāng)?shù)谝淮翁砑佑成潢P(guān)系時铜异,數(shù)組初始化為一個長度為16的HashMap$Entry的數(shù)組,這個HashMap$Entry類型是實現(xiàn)了java.util.Map.Entry接口

(2)特殊考慮:如果key為null秸架,index直接是[0]

(3)在計算index之前揍庄,會對key的hashCode()值,做一個hash(key)再次哈希的運算咕宿,這樣可以使得Entry對象更加散列的存儲到table中

(4)計算index = table.length-1 & hash;

(5)如果table[index]下面币绩,已經(jīng)有映射關(guān)系的key與我要添加的新的映射關(guān)系的key相同了,會用新的value替換舊的value府阀。

(6)如果沒有相同的缆镣,會把新的映射關(guān)系添加到鏈表的頭,原來table[index]下面的Entry對象連接到新的映射關(guān)系的next中试浙。

(7)添加之前先判斷if(size >= threshold? &&? table[index]!=null)如果該條件為true董瞻,會擴容

if(size >= threshold? &&? table[index]!=null){

①會擴容

②會重新計算key的hash

③會重新計算index

}

3.put(key,value) -JDK1.8

(1)當(dāng)?shù)谝淮翁砑佑成潢P(guān)系時,數(shù)組初始化為一個長度為16的HashMap$Node的數(shù)組田巴,這個HashMap$Node類型是實現(xiàn)了java.util. Map.Entry接口

(2)在計算index之前钠糊,會對key的hashCode()值,做一個hash(key)再次哈希的運算壹哺,這樣可以使得Entry對象更加散列的存儲到table中

> JDK1.8關(guān)于hash(key)方法的實現(xiàn)比JDK1.7要簡潔抄伍, key.hashCode() ^ key.Code()>>16;(異或其高16位)

(3)計算index = table.length-1 & hash;

(4)如果table[index]下面,已經(jīng)有映射關(guān)系的key與我要添加的新的映射關(guān)系的key相同了管宵,會用新的value替換舊的value截珍。

(5)如果沒有相同的,

①table[index]鏈表的長度沒有達(dá)到8個箩朴,會把新的映射關(guān)系添加到尾部

②table[index]鏈表的長度達(dá)到8個岗喉,但是table.length沒有達(dá)到64,會先對table進(jìn)行擴容炸庞,然后再添加

③table[index]鏈表的長度達(dá)到8個钱床,并且table.length達(dá)到64,會先把該分支進(jìn)行樹化埠居,結(jié)點的類型變?yōu)門reeNode查牌,然后把鏈表轉(zhuǎn)為一棵紅黑樹

④table[index]本來就已經(jīng)是紅黑樹了,那么直接連接到樹中滥壕,可能還會考慮考慮左旋右旋以保證樹的平衡問題

(6)添加完成后判斷if(size > threshold ){

①會擴容

②會重新計算key的hash

③會重新計算index

}


二僧免、HashMap的各種參數(shù)

閾值 = size(數(shù)組大小)* loadFactory(加載因子)

初始化大小size為16捏浊,加載因子為0.75,JDK1.8鏈表長度為8,數(shù)組長度大于等于64撞叨,進(jìn)行樹化

(1)1. HashMap的負(fù)載因子是多少金踪,為什么浊洞?

a) 0.75;

b) 因為定的太大胡岔,比如為1法希,就意味著數(shù)組的空位都需要填滿,如果一直等到數(shù)組填滿才擴容靶瘸,雖然達(dá)到了最大的數(shù)組空間利用率苫亦,但會產(chǎn)生大量的哈希碰撞,同時產(chǎn)生更多的鏈表怨咪,顯然不符合我們的要求屋剑;

c) 但如果設(shè)置的太小,比如0.3诗眨,這樣一來保證了數(shù)組空間很充足唉匾,減少了哈希碰撞,這種情況下查詢效率很高匠楚,但是消耗浪費了大量的空間巍膘。

d) 所以我們需要在時間和空間上做一個折中,選擇最合適的負(fù)載因子以保證最優(yōu)化芋簿,0.75峡懈。

2. HashMap的數(shù)組長度是2的指數(shù)次冪,為什么与斤。

i. 通過tableSizeFor()方法讓最高位1的后面全變?yōu)?肪康,在讓結(jié)果n+1,即得到了2的整數(shù)次冪幽告。

ii. 因為添加元素時索引的下標(biāo)可以通過取模運算獲得梅鹦,但是取模的效率低于乘法,所以要避免頻繁的取模運算冗锁。有因為在我們HashMap中他要通過取模去定位我們的索引齐唆,并且hashmap是在不斷的擴容的,數(shù)組一旦達(dá)到容量閾值時就需要進(jìn)行擴容冻河,那么擴容就意味著要進(jìn)行數(shù)組元素的移動箍邮,每一次移動都要重新計算索引,這個過程中牽扯大量的元素移動叨叙,就需要頻繁的取模運算锭弊,就會大大影響效率。

iii. 那么如果我們直接使用與運算擂错,這個效率就遠(yuǎn)高與取模運算味滞。利用與運算的就需要規(guī)定好數(shù)組的長度n,將n-1就會得到最高位為0,后面全1的二進(jìn)制數(shù)剑鞍,與任何數(shù)相與得到的范圍在0~n-1昨凡。

iv. 結(jié)論:首先使用與運算來加快計算的效率,而要使用與運算蚁署,就需要數(shù)組長度n-1與hash值保證其在數(shù)組范圍內(nèi)便脊,只有當(dāng)數(shù)組的長度為2的指數(shù)次冪時,其計算出來的值才能和取模算法的值相等光戈,并且保證能取到數(shù)組中的每一位哪痰,減少哈希碰撞,不浪費大量數(shù)組資源久妆。

3. 為什么鏈表長度大于8時轉(zhuǎn)成紅黑樹晌杰?

涉及泊松分布,以下是通過泊松分布計算出來的鏈表中元素個數(shù)和概率的對照表镇饺,鏈表中元素個數(shù)為8的概率非常小乎莉。

另外,紅黑樹平均查找長度是log(n),長度為8時奸笤,平均查找長度為3惋啃,如果繼續(xù)使用鏈表,平均查找長度為8/2=4监右,才有轉(zhuǎn)換為樹的必要边灭。


三、并發(fā)下HashMap安全嗎健盒?為什么绒瘦?

線程不安全,因為在多線程下扣癣,transfer方法將原table的值賦值給新的table惰帽,而transfer使用的是頭插法,也就是鏈表的順序會翻轉(zhuǎn)父虑,從而可能形成循環(huán)鏈表该酗。

解決方法 : https://blog.csdn.net/javageektech/article/details/103724851

第一種方法,使用Hashtable線程安全類士嚎;

第二種方法呜魄,使用Collections.synchronizedMap方法,對方法進(jìn)行加同步鎖莱衩;

第三種方法爵嗅,使用并發(fā)包中的ConcurrentHashMap類;

前兩種方法都是通過給加全表鎖來保證安全笨蚁,在競爭激烈的多線程環(huán)境下性能非常差睹晒,所以不推薦使用趟庄!

,因為hashMap 是數(shù)組 + 鏈表的數(shù)據(jù)結(jié)構(gòu)册招,如果我們把數(shù)組進(jìn)行分割多段岔激,對每一段分別設(shè)計一把同步鎖,這樣在多線程訪問不同段的數(shù)據(jù)時是掰,就不會存在鎖競爭了,這樣是不是可以有效的提高性能辱匿?


四键痛、ConcurrentHashMap底層實現(xiàn)及其安全機制

好文:https://blog.csdn.net/javageektech/article/details/103724851

Jdk1.7實現(xiàn)方式ConcurrentHashMap類所采用的正是分段鎖的思想,將HashMap 進(jìn)行切割匾七,把HashMap 中的哈希數(shù)組切分成小數(shù)組絮短,每個小數(shù)組有n HashEntry 組成,其中小數(shù)組繼承自ReentrantLock(可重入鎖)昨忆,這個小數(shù)組名叫Segment丁频。

Jdk1.8實現(xiàn)方式:JDK1.8中 ConcurrentHashMap 類取消了Segment 分段鎖,采用CAS+synchronized來保證并發(fā)安全邑贴,數(shù)據(jù)結(jié)構(gòu)跟 jdk1.8 中 HashMap 結(jié)構(gòu)類似席里,都是數(shù)組 + 鏈表(當(dāng)鏈表長度大于 8 時,鏈表結(jié)構(gòu)轉(zhuǎn)為紅黑二叉樹)結(jié)構(gòu)拢驾。

ConcurrentHashMap 中synchronized 只鎖定當(dāng)前鏈表或紅黑二叉樹的首節(jié)點奖磁,只要節(jié)點 hash 不沖突,就不會產(chǎn)生并發(fā)繁疤,相比 JDK1.7 的 ConcurrentHashMap 效率又提升了 N 倍咖为!


一、Jdk1.7源碼分析:

1稠腊、 HashEntry和HashMap中的 Entry非常類似躁染,唯一的區(qū)別就是其中的核心數(shù)據(jù)如value ,以及next都使用了volatile關(guān)鍵字修飾架忌,保證了多線程環(huán)境下數(shù)據(jù)獲取時的可見性吞彤!

2、 Segment 這個靜態(tài)內(nèi)部類繼承了ReentrantLock類鳖昌,ReentrantLock是一個可重入鎖备畦。

3、 理論上 ConcurrentHashMap 支持 concurrentLevel(通過 Segment 數(shù)組長度計算得來许昨,默認(rèn)為16) 個線程并發(fā)操作懂盐,每當(dāng)一個線程獨占一把鎖訪問 Segment 時,不會影響到其他的 Segment 操作糕档,效率大大提升莉恼!

4拌喉、 Put方法的流程:

第一步,嘗試獲取對象鎖俐银,如果獲取到返回 true尿背,否則執(zhí)行scanAndLockForPut方法,這個方法也是嘗試獲取對象鎖捶惜;

第二步田藐,獲取到鎖之后,類似 hashMap 的 put 方法吱七,通過 key 計算所在 HashEntry 數(shù)組的下標(biāo)汽久;

第三步,獲取到數(shù)組下標(biāo)之后遍歷鏈表內(nèi)容踊餐,通過 key 和 hash 值判斷是否 key 已存在景醇,如果已經(jīng)存在,通過標(biāo)識符判斷是否覆蓋吝岭,默認(rèn)覆蓋三痰;

第四步,如果不存在窜管,采用頭插法插入到 HashEntry 對象中散劫;

第五步,最后操作完整之后微峰,釋放對象鎖舷丹;

上述提到的scanAndLockForPut方法,操作也是分以下幾步:

? 當(dāng)前線程嘗試去獲得鎖蜓肆,查找 key 是否已經(jīng)存在颜凯,如果不存在,就創(chuàng)建一個 HashEntry 對象仗扬;

? 如果重試次數(shù)大于最大次數(shù)症概,就調(diào)用lock()方法獲取對象鎖,如果依然沒有獲取到早芭,當(dāng)前線程就阻塞彼城,直到獲取之后退出循環(huán);

? 在這個過程中退个,key 可能被別的線程給插入募壕,所以在第 5 步中,如果 HashEntry 存儲內(nèi)容發(fā)生變化语盈,重置重試次數(shù)舱馅;

通過scanAndLockForPut()方法,當(dāng)前線程就可以在即使獲取不到segment鎖的情況下刀荒,完成需要添加節(jié)點的實例化工作代嗤,當(dāng)獲取鎖后棘钞,就可以直接將該節(jié)點插入鏈表即可。

這個方法還實現(xiàn)了類似于自旋鎖的功能干毅,循環(huán)式的判斷對象鎖是否能夠被成功獲取宜猜,直到獲取到鎖才會退出循環(huán),防止執(zhí)行 put 操作的線程頻繁阻塞硝逢,這些優(yōu)化都提升了 put 操作的性能姨拥。

5、 remove方法:

1) 先獲取對象鎖趴捅;

2) 計算 key 的 hash 值在 HashEntry[]中的角標(biāo)垫毙;

3) 根據(jù) index 角標(biāo)獲取 HashEntry 對象;

4) 循環(huán)遍歷 HashEntry 對象拱绑,HashEntry 為單向鏈表結(jié)構(gòu);

5) 通過 key 和 hash 判斷 key 是否存在丽蝎,如果存在猎拨,就移除元素,并將需要移除的元素節(jié)點的下一個屠阻,向上移红省;

6) 最后就是釋放對象鎖,以便其他線程使用国觉;

二吧恃、 jdk1.8源碼分析

1、 JDK1.8 中的 ConcurrentHashMap 對節(jié)點Node類中的共享變量麻诀,和 JDK1.7 一樣痕寓,使用volatile關(guān)鍵字,保證多線程操作時蝇闭,變量的可見行呻率!

2、 Put方法流程:

? 首先會判斷 key呻引、value 是否為空礼仗,如果為空就拋異常!

? 接著會判斷容器數(shù)組是否為空逻悠,如果為空就初始化數(shù)組元践;

? 進(jìn)一步判斷,要插入的元素f童谒,在當(dāng)前數(shù)組下標(biāo)是否第一次插入单旁,如果是就通過 CAS 方式插入;

? 在接著判斷f.hash == -1是否成立惠啄,如果成立慎恒,說明當(dāng)前f是ForwardingNode節(jié)點任内,表示有其它線程正在擴容,則一起進(jìn)行擴容操作融柬;

? 獲得該位置下的鎖死嗦,把新的Node節(jié)點按鏈表或紅黑樹的方式插入到合適的位置;

? 節(jié)點插入完成之后粒氧,接著判斷鏈表長度是否超過8越除,如果超過8個,就將鏈表轉(zhuǎn)化為紅黑樹結(jié)構(gòu)外盯;

? 最后摘盆,插入完成之后,進(jìn)行擴容判斷饱苟;

3孩擂、 initTable 初始化數(shù)組,當(dāng)?shù)谝淮尾迦霑r箱熬,內(nèi)部容器數(shù)組為空类垦,該方法進(jìn)行初始化

其中sizeCtl 是一個對象屬性,使用了 volatile 關(guān)鍵字修飾保證并發(fā)的可見性城须,默認(rèn)為 0蚤认,當(dāng)?shù)谝淮螆?zhí)行 put 操作時,通過Unsafe.compareAndSwapInt()方法糕伐,俗稱CAS砰琢,將 修改為 -1,有且只有一個線程能夠修改成功良瞧,接著執(zhí)行 table 初始化任務(wù)陪汽。

如果別的線程發(fā)現(xiàn)sizeCtl<0,意味著有另外的線程執(zhí)行 CAS 操作成功莺褒,當(dāng)前線程通過執(zhí)行Thread.yield()讓出 CPU 時間片等待 table 初始化完成掩缓。

4、 helpTransfer 幫組擴容遵岩,當(dāng)f.hash =-1時你辣,說明當(dāng)前f是一個forwardingNode節(jié)點,意味著其他線程正在擴容尘执,則一起進(jìn)行擴容操作舍哄。

這個過程,操作步驟如下:

? 第 1 步誊锭,對 table表悬、node 節(jié)點、node 節(jié)點的 nextTable(新table)進(jìn)行數(shù)據(jù)校驗丧靡;

? 第 2 步蟆沫,根據(jù)數(shù)組的 length 得到一個標(biāo)識符號籽暇;

? 第 3 步,進(jìn)一步校驗 nextTab饭庞、tab戒悠、sizeCtl 值,如果 nextTab 沒有被并發(fā)修改并且 tab 也沒有被并發(fā)修改舟山,同時 sizeCtl < 0绸狐,說明還在擴容;

? 第 4 步累盗,對 sizeCtl 參數(shù)值進(jìn)行分析判斷寒矿,如果不滿足任何一個判斷,將sizeCtl + 1, 增加了一個線程幫助其擴容;

5若债、 addCount擴容判斷

這個過程符相,操作步驟如下:

? 第 1 步,利用 CAS 將方法更新 baseCount 的值

? 第 2 步蠢琳,檢查是否需要擴容主巍,默認(rèn) check = 1,需要檢查挪凑;

? 第 3 步,如果滿足擴容條件逛艰,判斷當(dāng)前是否正在擴容躏碳,如果是正在擴容就一起擴容;

? 第 4 步散怖,如果不在擴容菇绵,將 sizeCtl 更新為負(fù)數(shù),并進(jìn)行擴容處理镇眷;

總結(jié):

為解決HashMap在多線程環(huán)境下操作不安全的問題咬最,java為我們提供了ConcurrentHashMap類,保證了多線程下hashMap操作安全欠动。

在jdk1.7中永乌,ConcurrentHashMap采用了分段鎖策略,將一個HashMap切割成Segment數(shù)組具伍,而Segment存儲n個HashEntry,類似HashMap翅雏,不同的是Segment繼承自ReetrantLock(可重入鎖),在操作的時候給Segment賦予一個對象鎖人芽,從而保證了多線程環(huán)境下并發(fā)操作安全望几。

但是jdk1.7中,hashMap容易因為沖突鏈表長度過長萤厅,導(dǎo)致查詢效率低橄抹。

在jdk1.8中靴迫,ConcurrentHashMap采用了jdk1.8中HashMap類似的存儲結(jié)構(gòu)(數(shù)組+鏈表/紅黑樹),但ConcurrentHashMap并沒有采用分段鎖的策略楼誓,而是在元素的節(jié)點上采用CAS+synchronized操作來保證并發(fā)的安全性玉锌。

五、?TreeMap和HashMap的區(qū)別

1慌随、 HashMap中元素是無序的芬沉;TreeMap中所有元素都是有某一固定順序的

2、 HashMap繼承AbstractMap類阁猜,是基于hash表實現(xiàn)的丸逸;而TreeMap繼承SortedMap類,是基于紅黑樹實現(xiàn)的剃袍。

3黄刚、 兩者都是線程不安全的

4、 HashMap適用于Map插入民效、刪除憔维、定位元素;TreeMap適用于自然順序或自定義順序遍歷鍵畏邢。

六业扒、HashMap與Hashtable的區(qū)別

1皿曲、hashtable是線程安全的,即hashtable的方法都提供了同步機制秀睛,底層加了synchronized關(guān)鍵字;hashmap不是線程安全的,即不提供同步機制?

2辽剧、hashtable不允許插入空值,hashmap允許!

3臂寝、HashMap繼承了AbstractMap章鲤,HashTable繼承Dictionary抽象類,兩者均實現(xiàn)Map接口咆贬。

4败徊、HashMap的初始容量為16,Hashtable初始容量為11掏缎,兩者的填充因子默認(rèn)都是0.75皱蹦。

5、HashMap擴容時是當(dāng)前容量翻倍即:capacity*2御毅,Hashtable擴容時是容量翻倍+1即:capacity*2+1根欧。

6、HashMap和Hashtable的底層實現(xiàn)都是數(shù)組+鏈表結(jié)構(gòu)實現(xiàn)端蛆。

7凤粗、兩者計算hash的方法不同:

Hashtable計算hash是直接使用key的hashcode對table數(shù)組的長度直接進(jìn)行取模:

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子嫌拣,更是在濱河造成了極大的恐慌柔袁,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件异逐,死亡現(xiàn)場離奇詭異捶索,居然都是意外死亡,警方通過查閱死者的電腦和手機灰瞻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進(jìn)店門腥例,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人酝润,你說我怎么就攤上這事燎竖。” “怎么了要销?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵构回,是天一觀的道長。 經(jīng)常有香客問我疏咐,道長纤掸,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任浑塞,我火速辦了婚禮借跪,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘酌壕。我一直安慰自己垦梆,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布仅孩。 她就那樣靜靜地躺著,像睡著了一般印蓖。 火紅的嫁衣襯著肌膚如雪辽慕。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天赦肃,我揣著相機與錄音溅蛉,去河邊找鬼。 笑死他宛,一個胖子當(dāng)著我的面吹牛船侧,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播厅各,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼镜撩,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了队塘?” 一聲冷哼從身側(cè)響起袁梗,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤宜鸯,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后遮怜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體淋袖,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年锯梁,在試婚紗的時候發(fā)現(xiàn)自己被綠了即碗。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡陌凳,死狀恐怖剥懒,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情冯遂,我是刑警寧澤蕊肥,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站蛤肌,受9級特大地震影響壁却,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜裸准,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一展东、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧炒俱,春花似錦盐肃、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至峦阁,卻和暖如春谦铃,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背榔昔。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工驹闰, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人撒会。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓嘹朗,卻偏偏與公主長得像,于是被迫代替她去往敵國和親诵肛。 傳聞我的和親對象是個殘疾皇子屹培,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,472評論 2 348

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

  • 今天感恩節(jié)哎,感謝一直在我身邊的親朋好友。感恩相遇惫谤!感恩不離不棄壁顶。 中午開了第一次的黨會,身份的轉(zhuǎn)變要...
    迷月閃星情閱讀 10,559評論 0 11
  • 彩排完溜歪,天已黑
    劉凱書法閱讀 4,197評論 1 3
  • 表情是什么若专,我認(rèn)為表情就是表現(xiàn)出來的情緒。表情可以傳達(dá)很多信息蝴猪。高興了當(dāng)然就笑了调衰,難過就哭了。兩者是相互影響密不可...
    Persistenc_6aea閱讀 124,435評論 2 7