回顧 kotlin 之 kotlin 基礎(chǔ)

[TOC]

kotlin 基礎(chǔ)

java 中有 main()方法作為程序的入口,那么在 kotlin 里邊也是類似的,也是提供了一個(gè)入口函數(shù),如下:

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

在 kotlin 定義一個(gè)函數(shù)(或者稱之為方法)是以fun開頭的,這有點(diǎn)類似于 JS 里邊的 function 似的.其中的args: Array<String>指的是這個(gè)函數(shù)的參數(shù),在 kotlin 中,參數(shù)類型是放在后邊而參數(shù)名是在前邊的,這個(gè)跟 java 中是正好相反的.
println(message)就是 kotlin 中的輸出語句,內(nèi)部實(shí)際調(diào)用了System.out.println(message).

基本語法

注釋

// 這是單行注釋
/*
*   這是多行注釋
*/
/**
* 這是文檔注釋
**/

變量

kotlin 中的變量,分為可變變量不可變變量.
可變變量用var修飾,一次賦值,支持多洗修改;不可變變量用val修飾(等價(jià)于 java 中用 final 關(guān)鍵字修飾的變量),一次賦值,不可更改.
kotlin 聲明變量的時(shí)候,類型是在后邊聲明的.
舉例:

var a: String = "a" // 聲明一個(gè) String 類型的變量 a
val b: String = "b" // 聲明一個(gè) String 類型的常量 b,不可重新賦值

a = "aa" // 沒問題
b = "bb" // 會(huì)報(bào)錯(cuò)
變量的數(shù)據(jù)類型

kotlin 中的數(shù)據(jù)類型,分為數(shù)值型,字符型,布爾型,數(shù)組性,字符串型等

數(shù)值類型
Byte,Float,Double,Int,Long,Short
布爾類型
Boolean
字符類型
Char
字符串類型
String
數(shù)組類型
常規(guī)使用是Array,但是針對(duì)某些特殊的比如 Int,Boolean 的數(shù)組,提供了特殊的格式IntArray,BooleanArray

舉例說明:

    var byte: Byte
    var float: Float = 1.0F
    var double: Double = 2.0
    var int: Int = 3
    var long: Long = 33
    var short: Short = 4
    var boolean: Boolean = false
    var char: Char = 'c'
    var string: String = "string"
    var intArray: IntArray = intArrayOf(1, 2, 3)
    var booleanArray: BooleanArray = booleanArrayOf(false, true)
    var stringArray: Array<String> = arrayOf("a", "b", "c")

運(yùn)算符

算術(shù)運(yùn)算符,賦值運(yùn)算符,比較運(yùn)算符,邏輯運(yùn)算符.跟 java 中沒什么區(qū)別

字符串

定義同 java 中的字符串,定義以及普通用法一樣一樣的...

    val s = "Hello Kotlin" // 定義一個(gè)字符串
    println(s)
    println(s[0]) // 根據(jù)索引值來獲取對(duì)應(yīng)位置上的字符
    for (c in s) { // 對(duì)字符串進(jìn)行遍歷
        print("$c,")
    }
    println()
    // 同時(shí),kotlin 標(biāo)準(zhǔn)庫中也提供了對(duì)應(yīng)的字符串遍歷的方法。
    s.forEach {
        print("$it,")
    }

kotlin 中一些增加的方法.

字符串查找
println(s.first()) // 獲取第一個(gè)字符
println(s.last()) // 獲取最后一個(gè)字符
println(s.get(1)) // 獲取索引值為 1 的字符
println(s.lastIndexOf("l")) // 獲取指定字符最有一次出現(xiàn)的索引值

字符串截取

方法同 java 中的 subString()

字符串替換

同 java 中的 replace()

模板表達(dá)式

java 中要使用一個(gè)變量,需要用+號(hào)拼起來用,如下

String a = "a";
String ab = a + "b";

但是 kotlin 中可以使用$來實(shí)現(xiàn)模板化,可以直接在雙引號(hào)之間引入你所需要的變量.單個(gè)引用可以省略掉{}

    val a = "a"
    val b = "${a}b"
    println("b = $b") // b = ab

選擇結(jié)構(gòu)語句

if 語句和 when(等同于 java 中的 switch/case) 語句

if 語句

if 語句的使用,跟 java 中一模一樣

    // if 語句
    val point = 60
    if (point < 60) {
        println("不及格")
    } else if (60 < point && point < 90) {
        println("良好")
    } else {
        println("優(yōu)秀")
    }

三元運(yùn)算符
kotlin 中不存在三元運(yùn)算符,但是可以使用如下實(shí)現(xiàn):

val result = if (point < 60) "淘汰" else "過關(guān)"
when 語句

when 語句其實(shí)就是 java 中的 switch/case 語句.

    // when 語句
    val season = 3
    val seasonResult = when (season) {
        1 -> "春季"
        3 -> "春季"
        6 -> "夏季"
        12 -> "冬季"
        else -> "未知季節(jié)"
    }

示例代碼中,將 when 語句的返回值賦給了一個(gè)變量,然后進(jìn)行輸出,可以看到, ->符號(hào)前邊的就是各種 case,后邊的就是需要匹配的內(nèi)容.
同時(shí)也支持多個(gè) case 匹配,比如 1,2,3 都是春季,那么可以采用如下寫法:

    val seasonResult = when (season) {
        1, 2, 3 -> "春季"
        4, 5, 6 -> "夏季"
        else -> "其他季節(jié)"
    }

循環(huán)結(jié)構(gòu)語句

while,do..while 等循環(huán)結(jié)構(gòu)都跟 java 中一樣,使用方法也是一樣的.主要學(xué)一下 for 循環(huán).
kotlin 中的 for 循環(huán)是這樣的.

for(循環(huán)對(duì)象 in 循環(huán)條件) {
    執(zhí)行語句
}

其中的in其實(shí)是 kotlin 中的范圍,

普通 for 循環(huán)

下邊的代碼就是循環(huán) 4 次,輸出 4 次日志.其中的in指的是范圍,1..4中的..指的是區(qū)間,等價(jià)于大于等于 1,小于等于 4,所以最后的實(shí)際輸出是 4 次.

    // for 循環(huán)
    for (i in 1..4) {
        println("string--->$i")
    }
forEach(),forEachIndexed()

kotlin 中還提供了兩個(gè)增強(qiáng)類型的for 循環(huán),主要針對(duì)數(shù)組和集合,但是所有對(duì)象都可用.
forEach{}: 接收一個(gè)閉包參數(shù)

    val forArray = arrayOf("a", "b", "c")
    forArray.forEach {
        println("forEach----$it")
    }

forEachIndexed{}: 兩個(gè)參數(shù),第一個(gè)是角標(biāo);第二個(gè)是元素

    forArray.forEachIndexed { index, it ->
        println("forEachIndexed----index=$index  it=$it")
    }

區(qū)間

區(qū)間指的是一類數(shù)據(jù)的集合,比如在數(shù)學(xué)中的[1,3],[1,3)等.

rangeTo(Int) & ..

rangeTo(Int)函數(shù)構(gòu)成了區(qū)間表達(dá),可以用..操作符來簡寫

    // 區(qū)間
    val qujian = 1.rangeTo(3) // 等價(jià)于 1 <= qujian <= 3
    for (index in qujian) {
        println("區(qū)間的值:$index")
    }

此處可以把rangeTo() 替換成..操作符來實(shí)現(xiàn),效果一致

until 操作符

假如我要實(shí)現(xiàn) 1 <= index < 3 ,kotlin 里邊怎么寫?
在 kotlin 中,有個(gè) until操作符,效果可以實(shí)現(xiàn)右邊開區(qū)間的效果,如下:

    // 輸出結(jié)果只有 1,2 兩個(gè)值,因?yàn)橛疫叢话?3
    for (index in 1 until 3) {
        println("until的值:$index")
    }
downTo(Int)

要是想實(shí)現(xiàn)逆序遍歷區(qū)間呢?
kotlin 里邊提供了downTo(Int)方便的實(shí)現(xiàn)逆序區(qū)間.

    // 輸出:3,2,1
    for (index in 3.downTo(1)) {
        println("區(qū)間的值:$index")
    }
步長 step

前邊說的區(qū)間,遍歷的時(shí)候都是步長是 1 的,也就是保證輸出是 1,2,3... 假如我要實(shí)現(xiàn)輸出 1,3,5...呢?
kotlin 里邊提供了step關(guān)鍵字,支持設(shè)置步長.使用很簡單,就是在循環(huán)條件之后加上step關(guān)鍵字,然后指定你需要的步長就行了,比如下邊是保證了輸出奇數(shù)...

    // 輸出 1,3,5,7,9
    for (index in 1..10 step 2) {
        println("step = $index")
    }

數(shù)組

kotlin 中的數(shù)組,用 Array 表示,通過泛型來控制數(shù)組中的元素類型.

    // 數(shù)組
    val array = arrayOf<String>("a", "b", "c")
    // 通過[]直接獲取索引值處的元素
    println("索引值為 1 的元素是:${array[1]}")
    println("索引值為 1 的元素是:${array.get(1)}")
    println("數(shù)組的長度是:${array.size}")
數(shù)組常見操作

遍歷
kotlin 中常見的遍歷方法有 for 循環(huán)遍歷和 forEach 遍歷,同時(shí)都提供了按照索引值遍歷的方案.

    // 遍歷
    array.forEach {
        println("數(shù)組元素:$it")
    }
    array.forEachIndexed { index, content ->
        println("數(shù)組元素:index=$index  content=$content")
    }
    for (content in array) {
        println("數(shù)組元素(for 循環(huán)):$content")
    }
    for ((index, content) in array.withIndex()) {
        println("數(shù)組元素(withIndex):index=$index content=$content")
    }

修改數(shù)組的值
kotlin 的數(shù)組中提供了set(index, value)方法用來修改指定索引值上的值,同時(shí)可以簡寫為[]

    array.set(1, "bb")
    array[1] = "bb"

獲取元素的索引值
通過indexOf(value)可以獲得指定元素在數(shù)組中的索引值.

    println("值為 b 的索引值是:${array.indexOf("b")}")

變量類型轉(zhuǎn)換

kotlin 中的類型轉(zhuǎn)換,包括智能類型轉(zhuǎn)換和強(qiáng)制類型轉(zhuǎn)換.

類型檢查

kotlin 中可以采用is或者!is來判斷是否是某種類型的.

    // 類型判斷
    val typeBoolean: Boolean = false
    println("typeBoolean 的類型是:${typeBoolean is Boolean}")
智能類型轉(zhuǎn)換

在 kotlin 中,經(jīng)過is類型判斷之后,kotlin 會(huì)智能的轉(zhuǎn)換成當(dāng)前判斷的類型

強(qiáng)制類型轉(zhuǎn)換

在 kotlin 中可以采用as關(guān)鍵字實(shí)現(xiàn)強(qiáng)制類型轉(zhuǎn)換,同時(shí)可以使用as?進(jìn)行安全的類型轉(zhuǎn)換.

    val aStr = "aaaa"
    val bString = aStr as String
    println("bString 的類型是:${bString.javaClass}") // class java.lang.String

接下來我嘗試將一個(gè) Int 類型的轉(zhuǎn)換成 String 類型的試試

    val aInt = 1
    val bInt = aInt as String
    println(bInt)

此時(shí)會(huì)報(bào)錯(cuò):
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String at com.yanftch.review.kotlinbasic.KtKt.main(Kt.kt:137)
這就是類轉(zhuǎn)換異常的報(bào)錯(cuò),那么在 kotlin 中該怎么避免你呢? 這就是下邊說的as?關(guān)鍵字了,他可以在上述情況下避免拋出異常.
所以上邊的代碼,如果采用 as? 的話,最后會(huì)正常輸出,但是輸出的值是 null

    val aInt = 1
    val bInt = aInt as? String
    println(bInt) // 輸出 null

空值處理

空指針異常是最常見的開發(fā)異常,那么 kotlin 中是怎么處理空指針異常呢?

可空類型變量 ?

在 kotlin 可以通過?指定一個(gè)變量是可空的變量,可空變量可以賦值為 null,

var name: String // 不可空變量
var age: Int? // 可空變量

上邊的代碼中,制定了 name 為不可空變量,那么如果給賦值 null 就會(huì)報(bào)錯(cuò),相反,age 變量指定了為可空變量,那么就可以賦值為 null.

安全調(diào)用符 ?.

當(dāng)一個(gè)變量為可空的時(shí)候,我們?cè)谑褂玫臅r(shí)候,需要對(duì)他做空判斷之后再用,kotlin 中可以直接使用?.操作符進(jìn)行可空類型的變量的調(diào)用,也不會(huì)出現(xiàn)任何問題.

val name: String? = null
print(name?.toString())
Elvis 操作符 ?:

采用 ?. 調(diào)用的時(shí)候,如果調(diào)用者是為空的,那么返回地同樣也是空, 如果我不想要 null 而是想要一個(gè)默認(rèn)值呢?那么很簡單,可以采用?:操作符, 他的用處是:調(diào)用者如果不為空,那么就返回該有的值(也就是?:前邊的值);調(diào)用者為空,那么就返回設(shè)置好的默認(rèn)值(也就是?:后邊的值)

    val name: String? = null
    val nameResult = name ?: "default"
    println("nameResult 的值是: $nameResult")

name 為空的時(shí)候,返回的值就是 "default",不為空,就返回 name 的實(shí)際值.

函數(shù)/方法

kotlin 中的函數(shù),也就是方法,用處跟java 中一樣,但是增加了一些自己的特性.

函數(shù)的定義

kotlin 中的函數(shù),需要通過關(guān)鍵字fun來定義. 通過一個(gè)簡單的函數(shù)來學(xué)習(xí)

    fun method(a: Int, b: Int): Int {
        val sum = a + b
        return sum
    }
  • fun: 函數(shù)的命名關(guān)鍵字
  • method: 函數(shù)的名字
  • (a: Int, b: Int): 表示的是兩個(gè)參數(shù),其中分號(hào)前邊是參數(shù)名稱,后邊是參數(shù)類型,多個(gè)參數(shù)之間用逗號(hào)分開
  • Int: 大括號(hào)前邊的這個(gè) Int 表示的是當(dāng)前函數(shù)的返回值類型.
  • val sum = a + b: 函數(shù)體
  • return sum: 表示的是函數(shù)的返回值.

如果一個(gè)函數(shù)不返回任何類型,那么實(shí)際是返回的Unit類似 java 中的void.可省略不寫.

函數(shù)的類型

函數(shù)整體分為:有(無)參函數(shù); 有(無)返回值函數(shù)

kotlin 中,如果函數(shù)體只有一行,那么可以省略返回值類型以及大括號(hào),用一行代碼來實(shí)現(xiàn),如下:

fun getAge() = 18
函數(shù)的參數(shù)

函數(shù)的參數(shù),主要將具名參數(shù)和默認(rèn)參數(shù).

具名參數(shù)
就是指的在使用的時(shí)候,顯示的表明參數(shù)的名稱,這樣可以忽略參數(shù)的順序

    // 具名函數(shù)
    fun method2(name: String, age: Int) {
        println("name=$name, age=$age")
    }
    // 調(diào)用
    method2(age = 18, name = "tom")

默認(rèn)參數(shù)
java 中可以通過方法重載,實(shí)現(xiàn)同名函數(shù),不同參數(shù),在 kotlin 中可以使用一個(gè)函數(shù)來實(shí)現(xiàn)類似重載的作用.
就是在函數(shù)的定義的時(shí)候,給某些指定的參數(shù)聲明默認(rèn)值.比如上邊的函數(shù),可以給 age 指定默認(rèn)為 20,那么就算是后續(xù)調(diào)用函數(shù)的時(shí)候,不設(shè)置 age 的值,他的輸出也是 20

    fun method2(name: String, age: Int = 20) {
        println("name=$name, age=$age")
    }
    // 調(diào)用
    method2(name = "tom") // 輸出:name=tom, age=20

面向?qū)ο?/h3>

會(huì) java 的,面向?qū)ο筮€需要說嗎?~~~

類與對(duì)象

類定義

聲明一個(gè)類,也是使用class關(guān)鍵字

class User1 constructor(name: String) {
    private var mName: String? = null
    private var mAge: Int = 0
    fun user1Method() {
        println("name=$mName,  age=$mAge")
    }
}

mName, mAge: 類屬性或者類成員變量
user1Method: 類方法

對(duì)象創(chuàng)建

在 java 中需要 通過 new關(guān)鍵字來實(shí)例化一個(gè)對(duì)象,但是在 kotlin 可以省略掉他.

val user1 = User1()

然后可以對(duì)應(yīng)的調(diào)用類的成員變量和函數(shù)

user1.mAge
user1.user1Method()

構(gòu)造函數(shù)

構(gòu)造函數(shù)可以對(duì)類中的一些變量進(jìn)行初始化操作賦值. kotlin 可以直接在類定義的時(shí)候指定構(gòu)造函數(shù),稱之為主構(gòu)造,然后可以在內(nèi)部創(chuàng)建次要構(gòu)造.
主構(gòu)造:
constructor修飾,作用于類頭和類名之間,如果沒有參數(shù)的話可以省略.

class User1 constructor(name: String) {}

如上就是通過主構(gòu)造函數(shù)給當(dāng)前類傳遞了一個(gè)參數(shù).
name 參數(shù)的使用的話,就是可以直接在 kotlin 中的init{}代碼塊中進(jìn)行處理.

class User1 constructor(name: String) {
    private var mName: String? = null

    init {
        this.mName = name
    }
}

次要構(gòu)造
一個(gè)類可以有多個(gè)次要構(gòu)造函數(shù).
也需要用那個(gè)關(guān)鍵字修飾

    // 定義次構(gòu)造函數(shù),傳遞兩個(gè)參數(shù),并調(diào)用主構(gòu)造函數(shù)
    constructor(name: String, age: Int) : this(name) {
        this.mAge = age
    }

this 關(guān)鍵字
作用同 java 中

類繼承

讓子類擁有父類的特性.java 中通過extends關(guān)鍵字實(shí)現(xiàn)子類繼承父類,kotlin 中通過:來實(shí)現(xiàn).
kotlin 中所有的類默認(rèn)是final 的,不能被繼承,所以你需要對(duì)你要繼承的類用 open 關(guān)鍵字修飾

class User2 constructor(name: String) : User1(name) {

}
// User1 只有一個(gè)構(gòu)造函數(shù),傳參 name,那么子類繼承時(shí)需要傳.
  • 單繼承:一個(gè)類只能有一個(gè)直接父類
  • 支持多層繼承
函數(shù)重寫

方法的重寫,存在于子類和父類之間,同 java 中,需要override修飾.

Any 和 Object

在 java 中,所有類的根本父類是 Object, 但是 Kotlin 中的根本父類是Any, Any 在運(yùn)行時(shí),會(huì)自動(dòng)映射成 Object 對(duì)象.

常見類

嵌套類

kotlin 中,一個(gè)類內(nèi)部再聲明一個(gè)類, 成為嵌套類,嵌套類默認(rèn)不持有外部的引用,因此不能訪問到外部的變量或者函數(shù),如果希望可以引用,需要將內(nèi)部的類,用inner關(guān)鍵字修飾.
如下代碼中, 在嵌套類里邊會(huì)報(bào)錯(cuò),提示找不到那兩個(gè)參數(shù).

class Outer {
    private var mName: String? = null
    private var mAge: Int = 0

    class Inner {
        init {
            println("name=$mName,  age=$mAge")
        }
    }
}

通過字節(jié)碼反編成 java 文件,發(fā)現(xiàn),不用inner修飾的內(nèi)部的類,其實(shí)等同于 java 中的靜態(tài)內(nèi)部類.加了修飾之后,就是普通的內(nèi)部類.

總結(jié)

數(shù)據(jù)類

在java 中,定義一個(gè)類,要想外部訪問,需要提供 set/get 方法,但是在 kotlin 中,只需要在類聲明的時(shí)候在class 前邊加上data關(guān)鍵字修飾就行了, 內(nèi)部自動(dòng)提供 set/get 方法.

data class DataClassModel(var name: String, var age: Int)
// 其他地方調(diào)用
println("${dataClassModel.age}, ${dataClassModel.name}")

DataClassModel 實(shí)例化之后,可以直接通過.來獲取對(duì)應(yīng)的屬性.

單例模式

集合

lambda 編程

泛型

Gradle

協(xié)程

DSL

kotlin 與 java 合作

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,488評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,034評(píng)論 3 414
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,327評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,554評(píng)論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,337評(píng)論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,883評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,975評(píng)論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,114評(píng)論 0 286
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,625評(píng)論 1 332
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,555評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,737評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,244評(píng)論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 43,973評(píng)論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,362評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,615評(píng)論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,343評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,699評(píng)論 2 370

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