JDK14新特性介紹

JDK14新特性介紹


描述

OpenJDK14是Java SE平臺(tái)的版本14的開(kāi)源參考實(shí)現(xiàn),由Java社區(qū)流程中的JSR 389指定 。2020年3月17日J(rèn)DK14達(dá)到一般可用性, 基于GPL協(xié)議的構(gòu)建許可文件可從Oracle獲得; 其他供應(yīng)商的二進(jìn)制文件將在不久之后。已通過(guò)JEP 2.0提案修訂的JEP流程提出并跟蹤了此版本的功能和時(shí)間表曹动。該發(fā)行版是使用JDK發(fā)行流程(JEP 3)制作的。

此次的更新包含了很多令人興奮的新功能∈樵冢總共有非常令人印象深刻的16個(gè)JDK增強(qiáng)建議(JEP)和69個(gè)新的API元素。


新功能

Records

Java是一種面向?qū)ο蟮恼Z(yǔ)言拆又。您可以創(chuàng)建類來(lái)保存數(shù)據(jù)儒旬,并使用封裝來(lái)控制如何訪問(wèn)和修改該數(shù)據(jù)。對(duì)象的使用使操作復(fù)雜的數(shù)據(jù)類型變得簡(jiǎn)單而直接帖族。這是Java如此流行作為平臺(tái)的原因之一栈源。缺點(diǎn)(到現(xiàn)在為止)是,創(chuàng)建數(shù)據(jù)類型非常冗長(zhǎng)竖般,即使在最直接的情況下也需要大量代碼甚垦。讓我們看一下基本二維點(diǎn)所需的代碼:

public class Point {
  private final double x;
  private final double y;

  public Point(double x, double y) {
    this.x = x;
    this.y = y;
  }

  public double getX() {
    return x;
  }

  public double getY() {
    return y;
  }
}

這14行代碼僅僅表示了2個(gè)值元。

JDK 14引入了記錄(records)作為預(yù)覽功能涣雕。預(yù)覽功能是一個(gè)新概念艰亮,使Java平臺(tái)的開(kāi)發(fā)人員可以在不使其成為Java SE標(biāo)準(zhǔn)一部分的情況下包括新的語(yǔ)言功能。通過(guò)這樣做挣郭,開(kāi)發(fā)人員可以嘗試這些功能迄埃,并提供反饋,以便在必要時(shí)在標(biāo)準(zhǔn)中設(shè)置功能之前進(jìn)行更改(甚至刪除功能)兑障。要使用預(yù)覽功能侄非,必須為編譯和運(yùn)行時(shí)指定命令行標(biāo)志--enable-preview。對(duì)于編譯旺垒,還必須指定-source標(biāo)志彩库。

記錄是表示數(shù)據(jù)類的一種簡(jiǎn)單得多的方法。如果以Point為例先蒋,代碼可以簡(jiǎn)化為一行:

public record Point(double x, double y) { }

這與代碼的可讀性無(wú)關(guān)骇钦。我們立即意識(shí)到,我們現(xiàn)在有了一個(gè)包含兩個(gè)稱為x和y的雙精度值的類竞漾,我們可以使用getX和getY的標(biāo)準(zhǔn)方法名稱進(jìn)行訪問(wèn)眯搭。

讓我們檢查一下記錄的一些細(xì)節(jié)窥翩。

首先,記錄是一種新的類型鳞仙,它是類的受限形式寇蚊,就像枚舉一樣。記錄具有名稱和狀態(tài)描述棍好,用于定義記錄的組成部分仗岸。在上面的Point示例中,狀態(tài)描述是double和x和y借笙。記錄是為了簡(jiǎn)化而設(shè)計(jì)的扒怖,因此它們不能擴(kuò)展任何其他類或定義其他實(shí)例變量。記錄中的所有狀態(tài)都是最終狀態(tài)业稼,因此不提供set方法盗痒。如果您需要任何一個(gè),則需要使用成熟的類低散。

記錄確實(shí)具有靈活性俯邓。

通常,構(gòu)造函數(shù)除了提供值外還需要提供其他行為熔号。如果是這種情況稽鞭,我們可以提供構(gòu)造函數(shù)的替代實(shí)現(xiàn):

record Range(int min, int max) {
  Range {
    if (min > max)
      throw new IllegalArgumentException(“Max must be >= min”);
  }
}

請(qǐng)注意,由于指定參數(shù)是多余的跨嘉,因此構(gòu)造方法的定義仍被縮寫(xiě)川慌。也可以聲明從狀態(tài)描述自動(dòng)派生的任何成員,因此祠乃,例如梦重,您可以提供toString ()或hashCode ()實(shí)現(xiàn)的替代方法。

instanceof

在某些情況下亮瓷,您不知道對(duì)象的確切類型琴拧。為了解決這個(gè)問(wèn)題,Java有instanceof運(yùn)算符嘱支,可用于針對(duì)不同類型進(jìn)行測(cè)試蚓胸。這樣做的缺點(diǎn)是確定了對(duì)象的類型。如果要使用顯式類型轉(zhuǎn)換除师,則必須使用顯式類型轉(zhuǎn)換:

if (o instanceof String) {
  String s = (String)o;
  System.out.println(s.length);
}

在JDK 14中沛膳,對(duì)instanceof運(yùn)算符進(jìn)行了擴(kuò)展,以允許除了類型之外還指定變量名汛聚。然后可以使用該變量而無(wú)需顯式強(qiáng)制轉(zhuǎn)換:

if (o instanceof String s)
  System.out.println(s.length);

變量的范圍限于在邏輯上正確使用的地方锹安,因此:

if (o instanceof String s)
  System.out.println(s.length);
else
  // s在這里超出范圍

該范圍也可以在條件語(yǔ)句中應(yīng)用,因此我們可以執(zhí)行以下操作:

if (o instanceof String s && s.length() > 4) ...

這是有意義的,因?yàn)閘ength()方法將只是被稱為如果 o為一個(gè)字符串叹哭。邏輯或運(yùn)算符不一樣:

if (o instanceof String s || s.length() > 4) ...

在這種情況下忍宋,無(wú)論o是否為String的結(jié)果,都需要對(duì)s.length()進(jìn)行求值风罩。從邏輯上講糠排,這不起作用,因此會(huì)導(dǎo)致編譯錯(cuò)誤超升。

使用邏輯非運(yùn)算符可以產(chǎn)生一些有趣的作用域效果:

if (!(o instanceof String s && s.length() > 3)
  return;
System.out.println(s.length());  // s 在這里

我已經(jīng)看到了對(duì)變量的范圍劃分方式的一些負(fù)面反饋入宦,但是,鑒于所有作用域都是完全合乎邏輯的廓俭,因此我認(rèn)為它非常有效云石。

已經(jīng)有計(jì)劃提供此功能的第二個(gè)預(yù)覽版本,該版本將擴(kuò)展模式匹配以與記錄一起使用研乒,并提供實(shí)現(xiàn)解構(gòu)模式的簡(jiǎn)單方法×芟酰可以在JEP 375中找到更多詳細(xì)信息雹熬。

有幫助的NullPointException

任何編寫(xiě)了多行Java代碼的人都將在某個(gè)時(shí)候遇到NullPointerException。未能初始化對(duì)象引用(或?qū)⑵溴e(cuò)誤地顯式設(shè)置為null)谣膳,然后嘗試使用該引用將導(dǎo)致引發(fā)此異常竿报。

在簡(jiǎn)單的情況下,找出問(wèn)題的原因很簡(jiǎn)單继谚。如果我們嘗試運(yùn)行以下代碼:

public class NullTest {
  List<String> list;
  public NullTest() {
    list.add("foo");
  }
}

生成的錯(cuò)誤是:

Exception in thread "main" java.lang.NullPointerException
            at jdk14.NullTest.<init>(NullTest.java:16)
            at jdk14.Main.main(Main.java:15)

由于我們?cè)诘?6行上引用列表烈菌,因此很明顯,列表是罪魁禍?zhǔn)谆模覀兛梢钥焖俳鉀Q問(wèn)題芽世。
但是,如果我們?cè)谶@樣的行中使用鏈接引用:

a.b.c.d = 12;

運(yùn)行此命令時(shí)诡壁,我們可能會(huì)看到如下錯(cuò)誤:

Exception in thread "main" java.lang.NullPointerException
    at Prog.main(Prog.java:5)

問(wèn)題在于我們無(wú)法由此確定異常是由于a為null济瓢,b為null還是c為null的結(jié)果。我們要么需要使用IDE中的調(diào)試器妹卿,要么更改代碼旺矾,將引用分隔到不同的行上。兩者都不是理想的夺克。

在JDK 14中箕宙,如果我們運(yùn)行相同的代碼,我們將看到類似以下內(nèi)容:

Exception in thread "main" java.lang.NullPointerException:
    Cannot read field "c" because "a.b" is null
    at Prog.main(Prog.java:5)

馬上铺纽,我們可以看到ab是問(wèn)題所在柬帕,并著手進(jìn)行糾正。我敢肯定,這將使許多Java開(kāi)發(fā)人員的生活更加輕松雕崩,絕對(duì)拍手叫好的魁索,更好的定位才是解決bug的最佳途徑。


新API

java.io

PrintStream有兩個(gè)新方法盼铁,write(byte [] buf)和writeBytes(byte [] buf)粗蔚。這些有效地做同樣的事情,等效于write(buf饶火,0鹏控,buf.length)。之所以擁有兩種不同的方法肤寝,是因?yàn)閷rite定義為拋出IOException(但是当辐,奇怪的是,從不拋出)鲤看,而writeBytes沒(méi)有缘揪。因此,選擇使用哪種方法取決于您是否希望使用try-catch塊包圍該調(diào)用义桂。

有一個(gè)新的注釋類型找筝,Serial。它旨在用于對(duì)序列化的編譯器檢查慷吊。特別是袖裕,此類型的注釋?xiě)?yīng)應(yīng)用于與序列化相關(guān)的方法和聲明為可序列化的類中的字段。(它在某些方面與Override注釋類似)溉瓶。

java.lang

Class類為新的Record功能提供了兩種方法:isRecord()getRecordComponents()急鳄。getRecordComponents()方法返回一個(gè)RecordComponent對(duì)象數(shù)組。RecordComponentjava.lang.reflect包中的新類堰酿,它具有11種方法來(lái)檢索內(nèi)容疾宏,例如注釋的詳細(xì)信息和泛型。

Record是一個(gè)簡(jiǎn)單的新類胞锰,它重寫(xiě)Object的equals灾锯,hashCode和toString方法。

NullPointerException現(xiàn)在作為有幫助的NullPointerExceptions功能的一部分覆蓋了Throwable中的getMessage方法嗅榕。

StrictMath類具有六個(gè)新方法顺饮,這些方法補(bǔ)充了需要檢測(cè)溢出錯(cuò)誤時(shí)使用的現(xiàn)有精確方法。新方法是decrementExact凌那,incrementExact和negateExact(所有方法都有int和long參數(shù)的兩個(gè)重載版本)兼雄。

java.lang.annotation

ElementType枚舉為Records添加了一個(gè)新的常量RECORD_TYPE。

java.lang.invoke

MethodHandles.Lookup類具有兩個(gè)新方法:

  • hasFullPrivilegeAccess帽蝶,如果要查找的方法同時(shí)具有PRIVATE和MODULE訪問(wèn)權(quán)赦肋,則返回true。
  • previousLookupClass,它報(bào)告此查找對(duì)象先前從其傳送過(guò)來(lái)的另一個(gè)模塊中的查找類佃乘,或者為null囱井。以前,我從未聽(tīng)說(shuō)過(guò)在Java上下文中進(jìn)行隱形傳送(僅在Doctor Who和Minecraft中)趣避。查找可能導(dǎo)致模塊之間的傳送庞呕。

java.lang.runtime

這是JDK 14中的新軟件包,只有一個(gè)類ObjectMethods程帕。這是記錄功能的低級(jí)部分住练,它具有單個(gè)方法(引導(dǎo)程序),該方法生成對(duì)象等于愁拭,hashCode和toString方法讲逛。

java.util.text

CompactNumberFormat類具有一個(gè)新的構(gòu)造函數(shù),該構(gòu)造函數(shù)為pluralRules添加了一個(gè)參數(shù)岭埠。這是一個(gè)String盏混,表示將Count關(guān)鍵字(例如“ one”)與實(shí)際整數(shù)關(guān)聯(lián)的多個(gè)規(guī)則。它的語(yǔ)法在Unicode Consortium的復(fù)數(shù)規(guī)則語(yǔ)法中定義枫攀。

java.util

HashSet類具有一個(gè)新方法toArray括饶,該方法返回一個(gè)數(shù)組,其運(yùn)行時(shí)組件類型為Object来涨,包含此集合中的所有元素。

java.util.concurrent.locks

LockSupport類具有一個(gè)新方法setCurrentBlocker启盛。LockSupport提供了暫存和取消暫存線程的功能(與不贊成使用的Thread.suspend和Thread.resume方法沒(méi)有相同的問(wèn)題)”钠現(xiàn)在可以設(shè)置getBlocker將返回的Object。從非公共對(duì)象調(diào)用無(wú)參數(shù)方法時(shí)僵闯,這很有用卧抗。

javax.lang.model.element

ElementKind枚舉具有三個(gè)新常量,用于記錄和模式匹配實(shí)例的特征鳖粟,即BINDING_VARIABLE社裆,RECORDRECORD_COMPONENT

javax.lang.model.util

該軟件包提供實(shí)用程序向图,以協(xié)助處理程序元素和類型泳秀。通過(guò)添加記錄,添加了一組新的抽象類和具體類來(lái)支持此功能榄攀。(示例是AbstractTypeVisitor14嗜傅,ElementScanner14和TypeKindVisitor14)。

org.xml.sax

一種新方法已添加到SAX XML解析器的ContentHandler接口檩赢。聲明方法接收XML聲明的通知吕嘀。在默認(rèn)實(shí)現(xiàn)的情況下,此操作無(wú)效。

JEP 370:外部?jī)?nèi)存訪問(wèn)API

這是作為孵化器模塊引入的偶房,以允許更廣泛的Java社區(qū)進(jìn)行測(cè)試趁曼,并在其成為Java SE標(biāo)準(zhǔn)的一部分之前集成反饋。它旨在替代sun.misc.Unsafejava.io.MappedByteBuffer棕洋。

外部存儲(chǔ)器訪問(wèn)API引入了三個(gè)主要抽象:

  • MemorySegment:提供對(duì)具有給定范圍的連續(xù)內(nèi)存區(qū)域的訪問(wèn)挡闰。
  • MemoryAddress:提供到MemorySegment的偏移量(基本上是一個(gè)指針)。
  • MemoryLayout:提供一種描述內(nèi)存段布局的方法拍冠,該方法大大簡(jiǎn)化了使用var句柄訪問(wèn)MemorySegment的過(guò)程尿这。使用此功能,無(wú)需根據(jù)內(nèi)存的使用方式來(lái)計(jì)算偏移量庆杜。例如射众,一個(gè)整數(shù)或長(zhǎng)整數(shù)數(shù)組的偏移量將有所不同,但將使用MemoryLayout透明地對(duì)其進(jìn)行處理晃财。

JVM改變

  • JEP 345: G1的NUMA感知內(nèi)存分配叨橱。這樣可以提高使用非均勻內(nèi)存體系結(jié)構(gòu)(NUMA)的大型計(jì)算機(jī)的性能。

  • JEP 363: 刪除并發(fā)標(biāo)記掃描(CMS)垃圾收集器断盛。從JDK 9開(kāi)始罗洗,G1已經(jīng)成為默認(rèn)的收集器,大多數(shù)(但不是全部)都認(rèn)為G1是CMS的高級(jí)收集器钢猛』锊耍考慮到維護(hù)兩個(gè)相似的配置文件收集器所需的資源,Oracle決定棄用CMS(在JDK 9中也是如此)命迈,現(xiàn)在將其刪除贩绕。如果您正在尋找一款高性能,低延遲替代壶愤,為什么不嘗試 Zing JVM的C4淑倾?

  • JEP 349: Java Flight Recorder事件流。通過(guò)啟用工具以異步方式訂閱Java Flight Recorder事件征椒,這可以對(duì)JVM進(jìn)行更實(shí)時(shí)的監(jiān)視娇哆。

  • JEP 364: macOS上的ZGC和 JEP 365:Windows上的ZGC。ZGC是實(shí)驗(yàn)性的低延遲收集器勃救,最初僅在Linux上受支持“郑現(xiàn)在,它已擴(kuò)展到macOS和Windows操作系統(tǒng)剪芥。

  • JEP 366: 棄用ParallelScavenge和SerialOld GC組合垄开。Oracle指出,很少有人會(huì)使用這種組合税肪,并且維護(hù)開(kāi)銷(xiāo)相當(dāng)大溉躲。期望在不久的將來(lái)某個(gè)時(shí)候可以刪除此組合榜田。


其它功能

有許多與OpenJDK的不同部分相關(guān)的JEP:

  • JEP 343:打包工具。這是一個(gè)簡(jiǎn)單的打包工具锻梳,基于從JDK 11中的Oracle JDK中刪除的JavaFX javapackager工具箭券。它有很多功能,因此我將在單獨(dú)的博客文章中詳細(xì)介紹疑枯。

  • JEP 352:非易失性映射字節(jié)緩沖區(qū)辩块。這添加了新的特定于JDK的文件映射模式,以便可以使用FileChannel API創(chuàng)建引用非易失性存儲(chǔ)器的MappedByteBuffer實(shí)例荆永。添加了一個(gè)新模塊jdk.nio.mapmode废亭,以允許將MapMode設(shè)置為READ_ONLY_SYNC或WRITE_ONLY_SYNC。

  • JEP 361:開(kāi)關(guān)表達(dá)式標(biāo)準(zhǔn)具钥。開(kāi)關(guān)表達(dá)式是JDK 12中添加到OpenJDK的第一個(gè)預(yù)覽功能豆村。在JDK 13中,反饋導(dǎo)致將break值語(yǔ)法更改為yield 值骂删。 在JDK 14中掌动,開(kāi)關(guān)表達(dá)式不再是預(yù)覽功能,并且已包含在Java SE標(biāo)準(zhǔn)中宁玫。

  • JEP 362:棄用Solaris和SPARC端口粗恢。由于Oracle不再開(kāi)發(fā)Solaris操作系統(tǒng)或SPARC芯片體系結(jié)構(gòu),因此他們不再需要繼續(xù)維護(hù)這些端口欧瘪。這些可能會(huì)被Java社區(qū)中的其他人所接受眷射。

  • JEP 367:刪除Pack 200工具和API。JDK 11中不推薦使用的另一個(gè)功能現(xiàn)在已從JDK 14中刪除佛掖。此壓縮格式的主要用途是用于applet使用的jar文件凭迹。鑒于瀏覽器插件已從Oracle JDK 11中刪除,這似乎是一個(gè)合理的功能苦囱。

  • JEP 368:文本塊。這些已作為預(yù)覽功能包含在JDK 13中脾猛,并且在JDK 14中繼續(xù)進(jìn)行第二次迭代(仍在預(yù)覽中)撕彤。文本塊提供了對(duì)多行字符串文字的支持。所做的更改是添加了兩個(gè)新的轉(zhuǎn)義序列猛拴。第一個(gè)通過(guò)在行的末尾添加\來(lái)抑制換行符的包含(這在軟件開(kāi)發(fā)的許多其他地方很常見(jiàn))羹铅。第二個(gè)是\ s,表示單個(gè)空格愉昆。這對(duì)于防止從文本塊中的行尾剝離空白很有用职员。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市跛溉,隨后出現(xiàn)的幾起案子焊切,更是在濱河造成了極大的恐慌扮授,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,734評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件专肪,死亡現(xiàn)場(chǎng)離奇詭異刹勃,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)嚎尤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)荔仁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人芽死,你說(shuō)我怎么就攤上這事乏梁。” “怎么了关贵?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,133評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵遇骑,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我坪哄,道長(zhǎng)质蕉,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,532評(píng)論 1 293
  • 正文 為了忘掉前任翩肌,我火速辦了婚禮模暗,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘念祭。我一直安慰自己兑宇,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布粱坤。 她就那樣靜靜地躺著隶糕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪站玄。 梳的紋絲不亂的頭發(fā)上枚驻,一...
    開(kāi)封第一講書(shū)人閱讀 51,462評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音株旷,去河邊找鬼再登。 笑死,一個(gè)胖子當(dāng)著我的面吹牛晾剖,可吹牛的內(nèi)容都是我干的锉矢。 我是一名探鬼主播,決...
    沈念sama閱讀 40,262評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼齿尽,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼沽损!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起循头,我...
    開(kāi)封第一講書(shū)人閱讀 39,153評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤绵估,失蹤者是張志新(化名)和其女友劉穎炎疆,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體壹士,經(jīng)...
    沈念sama閱讀 45,587評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡磷雇,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了躏救。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片唯笙。...
    茶點(diǎn)故事閱讀 39,919評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖盒使,靈堂內(nèi)的尸體忽然破棺而出崩掘,到底是詐尸還是另有隱情,我是刑警寧澤少办,帶...
    沈念sama閱讀 35,635評(píng)論 5 345
  • 正文 年R本政府宣布苞慢,位于F島的核電站,受9級(jí)特大地震影響英妓,放射性物質(zhì)發(fā)生泄漏挽放。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評(píng)論 3 329
  • 文/蒙蒙 一蔓纠、第九天 我趴在偏房一處隱蔽的房頂上張望辑畦。 院中可真熱鬧,春花似錦腿倚、人聲如沸纯出。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,855評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)暂筝。三九已至,卻和暖如春硬贯,著一層夾襖步出監(jiān)牢的瞬間焕襟,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,983評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工饭豹, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留胧洒,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,048評(píng)論 3 370
  • 正文 我出身青樓墨状,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親菲饼。 傳聞我的和親對(duì)象是個(gè)殘疾皇子肾砂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評(píng)論 2 354

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