《Kotlin實戰(zhàn)》學(xué)習(xí)筆記

第一章 定義和目的

kotlin的主要特征

  • 目標(biāo)平臺:服務(wù)器端踪区,Android及任何Java運行的地方
  • 靜態(tài)類型
  • 函數(shù)式和面向?qū)ο?/li>
  • 免費且開源

小結(jié)

  • fun關(guān)鍵字用來聲明函數(shù)热芹,val關(guān)鍵字和var關(guān)鍵字分別用來聲明只讀變量和可變變量
  • 字符串模板幫助你避免繁瑣的字符串連接互亮。在變量名稱前加上$前綴或者用${}包圍一個表達(dá)式,來把值注入到字符串中
  • 值對象類在Kotlin中以簡潔的方式表示
  • 熟悉的if現(xiàn)在是帶返回值的表達(dá)式
  • when表達(dá)式類似于Java中的switch但功能更強大
  • 在檢查過變量具有某種類型之后不必顯示地轉(zhuǎn)換它的類型:編譯器使用智能轉(zhuǎn)換自動幫你完成
  • for,while畏纲,和do-while循環(huán)與Java類似,但是for循環(huán)現(xiàn)在更加方便春缕,特別是當(dāng)你需要迭代map的時候盗胀,又或是迭代集合需要下標(biāo)的時候。
  • 簡潔的語法1..5會創(chuàng)建一個區(qū)間锄贼,區(qū)間和 數(shù)列允許Kotlin在for循環(huán)中使用統(tǒng)一的語法和同一套抽象機制票灰,并且還可以使用in運算符和!in運算符來檢查值是否屬于某一個區(qū)間
  • Kotlin中的異常處理和Java非常相似咱娶,除了Kotlin不要求你聲明函數(shù)可以拋出的異常

第三章 函數(shù)的定義和調(diào)用

創(chuàng)建集合

val set = hashSetOf(1,2,3,4,5,6)
val list = arrayListOf(1,2,3,4,5)
val map = mapOf(1 to "one",2 to "two",3 to "tree")

kotlin沒有自己的集合類米间,而是采用的標(biāo)準(zhǔn)的Java集合類,kotlin可以更容易地與Java代碼交互膘侮,可以調(diào)用變量的JavaClass查看變量的類型屈糊。

讓函數(shù)更好的調(diào)用

/**
 * 集合按規(guī)定格式轉(zhuǎn)換為字符串
 */
fun <T> joinToString(collection: Collection<T>,
                     separator: String,
                     prefix: String,
                     postfix: String
) :String{
    val result = StringBuilder(prefix)
    for ((index,element) in collection.withIndex()){
        if (index>0) result.append(separator)
        result.append(element)
    }
    result.append(postfix)
    return  result.toString()
}

調(diào)用println(joinToString(set,",","[","]"))
結(jié)果:[1,2,3,4,5,6]
joinToString是kotlin集合類默認(rèn)的方法,可以直接用

命名參數(shù)

命名參數(shù)

可以顯示地表明一些參數(shù)的名稱琼了,如果在調(diào)用一個參數(shù)時逻锐,指明了一個參數(shù)的名稱,為了避免混淆雕薪,那它以后的所有參數(shù)都需要標(biāo)明名稱昧诱。

默認(rèn)參數(shù)值

當(dāng)使用常規(guī)的調(diào)用語法時,必須按照函數(shù)聲明中定義的參數(shù)順序來給定參數(shù)所袁,可以省略的只有排在末尾的參數(shù)盏档。如果使用命名參數(shù),可以省略中間的一些參數(shù)燥爷,也可以以你想要的任意順序只給定你需要的參數(shù)蜈亩。

fun main(args: Array<String>) {
    println(joinToString(set,",","[","]"))
    println(joinToString(set,",","["))
    println(joinToString(set,","))
    println(joinToString(set,postfix = "}",prefix = "{"))
}

/**
 * 集合按規(guī)定格式轉(zhuǎn)換為字符串
 */
fun <T> joinToString(collection: Collection<T>,
                     separator: String = ",",
                     prefix: String = "[",
                     postfix: String = "]"
) :String{
    val result = StringBuilder(prefix)
    for ((index,element) in collection.withIndex()){
        if (index>0) result.append(separator)
        result.append(element)
    }
    result.append(postfix)
    return  result.toString()
}
默認(rèn)參數(shù)值

消除靜態(tài)工具類:頂層函數(shù)和屬性

在Kotlin中懦窘,不需要去創(chuàng)建一個類作為靜態(tài)函數(shù)的容器,相反稚配,可以把這些函數(shù)直接放在代碼文件的頂層畅涂,不用從屬于任何的類。這些放在 文件頂層的函數(shù)依然的包內(nèi)的成員道川,如果你需要從包外訪問它午衰,則需要import,但不需要額外包一層。Kotlin編譯生成的類的名稱冒萄,對應(yīng)于包含函數(shù)的文件的名稱臊岸,這個文件中的所有頂層函數(shù)編譯為這個類的靜態(tài)函數(shù),因為Java要調(diào)用這個函數(shù)的時候和調(diào)用靜態(tài)函數(shù)一樣
改變包含Kotlin頂層函數(shù)的生成的類的名稱尊流,需要為這個文件添加@JvmName的注解扇单,將其放到這個文件的開頭,位于包名的前面奠旺。

頂層屬性

和函數(shù)一樣,頂層屬性和頂層函數(shù)一樣可以放在文件的頂層施流,和其它屬性一樣响疚,val只有一個getter,var對應(yīng)一對getter和setter,如果想要把一個常量public static final的屬性暴露給Java,可以用const來修飾它

給別人的類添加方法:擴展函數(shù)和屬性

fun String.lastChar(): Char = this.get(this.length - 1)

擴展函數(shù)就是一個類的成員函數(shù)瞪醋,不過定義在類的外面忿晕,所要做的就是把要擴展的類或者接口的名稱,放到即將添加的函數(shù)前面银受,這個類的名稱稱為接收者類型践盼;用來調(diào)用這個擴展函數(shù)的那個對象,叫做接收對象宾巍。

import string.lastChar

fun main(args: Array<String>) {
    println("Hello".lastChar())
}

導(dǎo)入函數(shù)還可以用as改名

import string.lastChar as last
fun main(args: Array<String>) {
    println("Hello".last())
}

Java中調(diào)用kotlin的函數(shù)就是調(diào)用kotlin生成的類文件的靜態(tài)方法咕幻,比如剛才那個方法如果聲明在StringUtil.kt的文件中,java中

char c = StringUtilkt.lastChar("Java")

擴展函數(shù)無非就是靜態(tài)函數(shù)的一個高效的語法糖顶霞,可以使用具體的類型作為接收者類型肄程,而不是一個類。

不可重寫擴展函數(shù)

擴展函數(shù)并不是類的一部分选浑,它是聲明在類之外的蓝厌。
如果一個類的成員函數(shù)和擴展函數(shù)有相同的簽名,成員函數(shù)往往會被優(yōu)先調(diào)用古徒。

擴展屬性

擴展屬性提供了一種方法拓提,用來擴展類的API,可以用來訪問屬性隧膘,用的是屬性語法而不是函數(shù)的語法代态。

val String.lastChar: Char
    get()=get(length-1)

調(diào)用

fun main(args: Array<String>) {
    println("Hello".lastChar)
}

可變屬性

var StringBuilder.builderLastChar: Char
    get()=get(length-1)
    set(value :Char) = this.setCharAt(length-1,value)

就是一個set和一個get

處理集合:可變參數(shù)寺惫,中綴調(diào)用和庫的支持

可變參數(shù):讓函數(shù)支持任意數(shù)量的參數(shù)

vararg 修飾可變參數(shù),數(shù)組變量前加*表示展開這個集合

fun zhankaiArgs(vararg args: Int){
    for ( e in args){
    print("$e  ")
    }
}

fun main(args: Array<String>) {
 val list = intArrayOf(1,3,4,5,6)
    zhankaiArgs(1,*list)
}

鍵值對的處理:中綴調(diào)用和解構(gòu)聲明

1.to("one) //一般to函數(shù)的調(diào)用
1 to "one"  //使用中綴符號調(diào)用to函數(shù)

中綴調(diào)用可以與只有一個參數(shù)的函數(shù)一起使用胆数,無論是普通的函數(shù)還是擴展函數(shù)肌蜻。要允許使用中綴符號調(diào)用函數(shù),需要使用infix修飾符來標(biāo)記它必尼。

infix fun Any.to(other:Any) = Pair(this,other)
//使用
 val pair = 2 to "two"
    print(pair)
//mapOf的聲明
public fun <K, V> mapOf(vararg pairs: Pair<K, V>): Map<K, V> 

結(jié)果:(2蒋搜,two),一個Pair對象就是一個鍵值對

字符串和正則表達(dá)式的處理

//分割表達(dá)式
val s="12.345-6.A".split("\\.|-".toRegex())//用正則表達(dá)式
val s2="12.345-6.A".split(".","-")//指定多個分隔符
//print結(jié)果都為[12, 345, 6, A]

使用String的擴展函數(shù) 解析文件路徑string

fun parsePath(path:String){
    val directory = path.substringBeforeLast("/")
    val fullName = path.substringAfterLast("/")

    val fileName = fullName.substringBeforeLast(".")
    val extension = fullName.substringAfterLast(".")
    print("directory: $directory  fullName: $fullName fileName: $fileName extention: $extension")
}

結(jié)果:

directory: H:/Users/yorl/kotlin-book fullName: chater.adoc fileName: chater extention: adoc

使用正則表達(dá)式解析

fun regexParsePath(path:String){
    val regex="""(.+)/(.+)\.(.+)""".toRegex()
    val matchResult = regex.matchEntire(path)
    if (matchResult!=null){
        val (directory,fileName,extention) = matchResult.destructured
        println("directory: $directory  fileName: $fileName extention: $extention")
    }
}

在三重引號字符串中,不需要對任何字符串進(jìn)行轉(zhuǎn)義判莉,包括反斜線

讓代碼更整潔:局部函數(shù)和擴展

如果一個函數(shù)內(nèi)有一些重復(fù)操作豆挽,可以使用局部函數(shù),局部函數(shù)可以訪問所在函數(shù)中的所有參數(shù)和變量券盅。

fun saveUser(user:User){
    fun validate(value:String, fieldName:String){
        if (value.isEmpty()){
            throw IllegalArgumentException(
                    "Can't save user ${user.id}: empty $fieldName"
            )
        }
    }
    validate(user.name,“Name”)
    validate(user.name,“Address”)
    //...
}

進(jìn)一步改進(jìn)

fun saveUser(user:User){
   user.validateBeforeSave()
    //...
}

fun User.validateBeforeSave(){
    fun validate(value :String, fieldName :String){
        if (value.isEmpty()){
            throw IllegalArgumentException(
                    "Can't save user ${id} : empty $fieldName"
            )
        }
    }
    validate(name,"Name")
    validate(adress,"Address")
}

可以看到擴展函數(shù)也可以用局部函數(shù)

小結(jié)

  • kotlin沒有定義自己的集合類帮哈,而是在Java集合類的基礎(chǔ)上提供了更豐富的API。
  • Kotlin可以給函數(shù)參數(shù)定義默認(rèn)值锰镀,這樣大大降低了重載函數(shù)的必要性娘侍,而且命名參數(shù)讓多參數(shù)函數(shù)的調(diào)用更加易讀
  • Kotlin可以用擴展函數(shù)和屬性來擴展任何類的API,包括在外部庫中定義的類泳炉,而不需要修改其源代碼憾筏,也沒有運行時開銷
  • 中綴調(diào)用提供了單個參數(shù)的,類似調(diào)用運算符方法的簡明語法
  • Kotlin為普通字符串和正則表達(dá)式都提供了大量的方便字符串處理的函數(shù)花鹅。
  • 三重引號的字符串提供了一種簡潔的方式氧腰,解決了原本在java中需要啰嗦的的轉(zhuǎn)義和字符串連接的問題
  • 局部函數(shù)幫助保持代碼整潔的同時,避免重復(fù)

第四章 類刨肃,對象和接口

Kotlin的類和接口與Java的類和接口有一點區(qū)別古拴,例如,接口可以包含屬性聲明真友,與Java不同黄痪,Kotlin的聲明默認(rèn)是final和public的,此外锻狗,嵌套的類默認(rèn)并不是內(nèi)部類满力,它們并沒有包含對其外部類的隱式引用。

4.1 定義類繼承結(jié)構(gòu)

kotlin的接口

  • 使用interface關(guān)鍵字聲明接口.
  • Kotlin在類名后面使用冒號代替了Java中的extends和implements關(guān)鍵字轻纪,和Java一樣油额,一個類可以實現(xiàn)任意多個接口,但是只能繼承一個類刻帚。override修飾符用來標(biāo)注被重寫的父類或者接口中的方法和屬性潦嘶,并且是kotlin中的override修飾符是強制要求的。
  • 接口的方法可以有一個默認(rèn)實現(xiàn)

interface Clickable{
    fun click()
    fun showOff()=println(" I'm clickable!")
}

interface  Focusable{
    fun setFocus(b: Boolean){
        println("I ${if(b) "got" else "lost"} focus.")
    }
    fun showOff() = println("I'm focusable!")
}
class Button:Clickable,Focusable{
    override fun click() {
        println("I was Clicked!")
    }

    /**
     * 兩個接口有同樣的函數(shù)下崇众,必須自己顯示實現(xiàn)
     */
    override fun showOff() {
        super<Clickable>.showOff()//可調(diào)用接口的默認(rèn)實現(xiàn)
        super<Focusable>.showOff()
    }
    //或者
//    override fun showOff() = super<Clickable>.showOff()
}

open,final和abstract修飾符:默認(rèn)為final

java的類和方法默認(rèn)是open的掂僵,而kotlin默認(rèn)是final的航厚,如果想允許創(chuàng)建一個類的子類,需要使用open修飾符來標(biāo)示這個類锰蓬,此外幔睬,需要給每一個可以被重寫的屬性或方法添加open修飾符


open class RichButton:Clickable{//這個類是open的,其它類可以繼承它
    fun desable(){}//這個函數(shù)是final的芹扭,不能在子類重寫它
    open fun animate(){}//這個函數(shù)是open的麻顶,可以在子類重寫它
    override fun click() {//這個函數(shù)重寫了一個open函數(shù)并它本身同樣是open的
        println("I'm clicked!")
    }
    final override fun showOff() =super.showOff()//聲明這個函數(shù)在子類不可重寫
}

注意:如果重寫了一個基類或者接口的成員,重寫了的成員同樣默認(rèn)是open的舱卡,如果想改變這一行為辅肾,阻止你的類的子類重寫你的子類,可以顯示地標(biāo)注為final

abstract 聲明抽象類轮锥,這種了不能實例化矫钓,一個抽象類通常包含一些沒有實現(xiàn)并且必須在子類重寫的抽象成員,抽象成員始終是open的舍杜,所有不需要顯示的使用open修飾符

abstract class Animated{//類是抽象的新娜,不能被實例化,所有是open的
    abstract fun animate()//函數(shù)的抽象的既绩,必須被子類實現(xiàn)
    open fun stopAnimating(){}//抽象類的非抽象函數(shù)并不是默認(rèn)open的杯活,但是可以標(biāo)注為open的
    fun animateTwice(){}
}
修飾符 相關(guān)成員 評注
final 不能被重寫 類中成員默認(rèn)使用
open 可以被重寫 需要明確的表明
abstract 必須被重寫 只能在抽象類中使用;抽象成員不能有實現(xiàn)
override 重寫父類或接口中的成員 如果沒有使用final,重寫的成員默認(rèn)是開放的

可見性修飾符:默認(rèn)為public

Javaz中的默認(rèn)可見性--包私有熬词,在Kotlin中并沒有使用,Kotlin只把包作為在命名空間里組織代碼的一種方式使用吸重,并沒有將其用作可見性控制互拾。Kotlin提供了一個新的修飾符,internal,表示只在模塊內(nèi)部可見嚎幸,一個模塊就是一組一起編譯的kotlin文件

修飾符 類成員 頂層聲明
public(默認(rèn)) 所有地方可見 所有地方可見
internal 模塊中可見 模塊中可見
protected 子類中可見 -
private 類中可見 文件中可見

內(nèi)部類和嵌套類:默認(rèn)是嵌套類

類A在另一個類B中聲明 在Java中 在Kotlin中
嵌套類(不存儲外部類的引用) static class A class A
內(nèi)部類(存貯外部類的引用) class A inner Class A
/**
 * 內(nèi)部類
 */
class Outer{
    inner class Inner{
        fun getOuterReference(): Outer = this@Outer //獲取外部類的引用
    }
}

密封類:定義受限的類繼承結(jié)構(gòu)

**
 * 密封類颜矿,Expr2包括了所有的子類
 */
sealed class Expr2{
    class Num(val value: Int): Expr2()
    class Sum(val left: Expr2,val right: Expr2):Expr2()
}

fun eval2(e: Expr2):Int =
        when(e){//when 表達(dá)式涵蓋了所有可能的情況,所以不在需要else分支
            is Expr2.Num -> e.value
            is Expr2.Sum -> eval2(e.left)+ eval2(e.right)
        }

4.2 聲明一個帶非默認(rèn)構(gòu)造方法或?qū)傩缘念?/h2>

初始化類:主構(gòu)造函數(shù)和初始化語句塊


//class User3(val nickName:String) //"val"意味著相應(yīng)的屬性會用構(gòu)造方法的參數(shù)來初始化

class User3 constructor(_nickName: String){//帶一個參數(shù)的主構(gòu)造方法
    val nickName: String
    init {
        nickName = _nickName //初始化語句塊
    }
}

如上圖是兩種聲明類的方式嫉晶,方式二用到了關(guān)鍵字constructor和init骑疆,constructor用來開始一個主構(gòu)造方法或從構(gòu)造方法的聲明,init用來引入一個初始化語句塊替废,這種語句快包含了在類被創(chuàng)建時執(zhí)行的代碼箍铭,并會與主構(gòu)造方法一起使用。

當(dāng)然再簡化可以這樣:

class User5 constructor(_nickName: String){//帶一個參數(shù)的主構(gòu)造方法
    val nickName =_nickName
}

構(gòu)造方法:用不同的方式來初始化父類

//用不同的方法來初始化父類
class Context
class Attribute

open class View {
    protected var name: String="View"
    val context: Context
    val attr: Attribute?

    constructor(ctx: Context)
            :this(ctx,null)

    constructor(ctx: Context,art: Attribute?){
        context=ctx
        attr=art
    }

    override fun toString(): String {
        return "View(name='$name')"
    }

}

class MyButton: View{
    constructor(ctx: Context)
    :this(ctx,null){
        name="MyButton"
    }
    constructor(ctx: Context,art: Attribute?)
    :super(ctx=ctx,art = art)

    override fun toString(): String{
        return "Mybutton(name=${name})"
    }
}

實現(xiàn)在接口中聲明的屬性

// 實現(xiàn)在接口中聲明的屬性

interface  UserInterface{
    val nickName: String //聲明屬性
}
//只填寫了昵稱的用戶
class PrivateUser(override val nickName: String):UserInterface //主構(gòu)造方法屬性
//提供了email進(jìn)行注冊的用戶
class SubscribingUser(val mail: String):UserInterface{
    override val nickName: String
        get() = mail.substringBefore("@")//自定義屬性及getter
}
//共享了Facebook賬戶的用戶
class FacebookUser(val accountId: Int):UserInterface{
    override val nickName = getFacebookName(accountId)//屬性初始化
    /**
     * 由id獲取用戶名
     */
    fun getFacebookName(accountId: Int): String{
        return "facebook:"+accountId
    }
}

通過getter和setter訪問支持字段


/**
 *通過getter或setter訪問支持字段
 */
class User2(val name: String){
    var address: String ="unspecified"
    set(value) {
        println("""
            Address was changed for $name:
            "$field" -> "$value".""".trimIndent())
        field=value
    }
}

修改訪問器的可見性

/**
 * 修改訪問器的可見性
 */
class LengthCounter{
    var counter: Int =0
        private set //不能在類外部修改這個屬性
    fun addWord(word: String){
        counter +=word.length
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末椎镣,一起剝皮案震驚了整個濱河市诈火,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌状答,老刑警劉巖冷守,帶你破解...
    沈念sama閱讀 211,348評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件刀崖,死亡現(xiàn)場離奇詭異,居然都是意外死亡拍摇,警方通過查閱死者的電腦和手機亮钦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來充活,“玉大人蜂莉,你說我怎么就攤上這事】疤疲” “怎么了巡语?”我有些...
    開封第一講書人閱讀 156,936評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長淮菠。 經(jīng)常有香客問我男公,道長,這世上最難降的妖魔是什么合陵? 我笑而不...
    開封第一講書人閱讀 56,427評論 1 283
  • 正文 為了忘掉前任枢赔,我火速辦了婚禮,結(jié)果婚禮上拥知,老公的妹妹穿的比我還像新娘踏拜。我一直安慰自己,他們只是感情好低剔,可當(dāng)我...
    茶點故事閱讀 65,467評論 6 385
  • 文/花漫 我一把揭開白布速梗。 她就那樣靜靜地躺著,像睡著了一般襟齿。 火紅的嫁衣襯著肌膚如雪姻锁。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,785評論 1 290
  • 那天猜欺,我揣著相機與錄音位隶,去河邊找鬼。 笑死开皿,一個胖子當(dāng)著我的面吹牛涧黄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播赋荆,決...
    沈念sama閱讀 38,931評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼笋妥,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了窄潭?” 一聲冷哼從身側(cè)響起挽鞠,我...
    開封第一講書人閱讀 37,696評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后信认,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體材义,經(jīng)...
    沈念sama閱讀 44,141評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,483評論 2 327
  • 正文 我和宋清朗相戀三年嫁赏,在試婚紗的時候發(fā)現(xiàn)自己被綠了其掂。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,625評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡潦蝇,死狀恐怖款熬,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情攘乒,我是刑警寧澤贤牛,帶...
    沈念sama閱讀 34,291評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站则酝,受9級特大地震影響殉簸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜沽讹,卻給世界環(huán)境...
    茶點故事閱讀 39,892評論 3 312
  • 文/蒙蒙 一般卑、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧爽雄,春花似錦蝠检、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至乘盖,卻和暖如春本慕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背侧漓。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留监氢,地道東北人布蔗。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像浪腐,于是被迫代替她去往敵國和親纵揍。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,492評論 2 348

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