Kotlin-面向?qū)ο?基礎(chǔ)

方法

Kotlin 中方法和函數(shù)其實是統(tǒng)一的衡未,但是我們這么理解區(qū)別:
函數(shù):直接定義在文件中的 fun辈挂。
方法:定義在 class 中的 fun召川。

方法和函數(shù)一樣冰蘑,也是可以賦值給其他對象,也使用雙冒號::運算符评汰。
函數(shù)::函數(shù)名纷捞。
方法類名::方法名

fun main() {
    // 以下兩種函數(shù)類型等價
    val a1: (Int) -> Int = ::test
    val a2: Function1<Int, Int> = ::test
    // 以下三種函數(shù)類型等價
    val b1: (Dog, String) -> String = Dog::eat
    val b2: Dog.(String) -> String = Dog::eat
    val b3: Function2<Dog, String, String> = Dog::eat
    // 注:FunctionN<A, B, ...>:N為參數(shù)加返回值個數(shù)被去,<>中依次寫入 類名主儡,參數(shù)類型(0~n)個,返回值類型(0~1)個
    
    println(a1.invoke(2)) //4
    println(a2(3)) //9
    println(b1.invoke(Dog(), "bone1")) //Dog is eating bone1
    println(b2(Dog(), "bone2")) //Dog is eating bone2
    println(b3.invoke(Dog(), "bone3")) //Dog is eating bone3
}

// 定義函數(shù)
fun test(a: Int) = a * a

// 定義類
class Dog {
    // 定義方法
    fun eat(food: String) = "Dog is eating $food"
}

注:函數(shù)類型均可省略惨缆,因為編譯器可以自動推斷出來糜值。

FunctionN<A, B, ...>
N:參數(shù)加返回值個數(shù)
<>:依次寫入 類名,參數(shù)類型(0 ~ n)個坯墨,返回值類型(0 ~ 1)個


中綴表示法

Koltin 中的方法也可以使用 infix 來修飾寂汇,寫法就和雙目運算符一樣。
需要注意的是:infix 方法只能有一個參數(shù)捣染,因為雙目運算符的后面只能帶一個參數(shù)骄瓣。


componentN 方法與解構(gòu)

Kotlin 允許將一個對象的 N 個屬性 “解構(gòu)” 給多個變量,寫法如下:
var (name, age) = user
Kotlin 實際會執(zhí)行的代碼:
var name = user.component1()
var age = user.component2()
如果希望將對象解構(gòu)成多個變量的話耍攘,那就需要定義多個 componentN() 方法榕栏,且該方法需要使用 operator 修飾。

class User(private var name: String, private var age: Int) {

    operator fun component1() = this.name

    operator fun component2() = this.age
}

fun main() {
    // 解構(gòu) User
    val (name, age) = User("張三", 28)
    println("$name 今年的年齡是 $age 歲") //張三 今年的年齡是 28 歲
    // 只解構(gòu) User 的部分屬性蕾各,如果想忽略前面屬性扒磁,可使用 _ 來代替
    val (name2) = User("李四", 29)
    println("用戶的名字是 $name2") //用戶的名字是 李四
    val (_, age2) = User("王五", 30)
    println("用戶的年齡是 $age2 歲") //用戶的年齡是 30 歲
}

如果只想解構(gòu)部分屬性,那忽略前面屬性可以使用 _ 來占位式曲。


數(shù)據(jù)類 data class

數(shù)據(jù)類專門用來封裝數(shù)據(jù)妨托,由于簡化 Java 中某些只定義fieldgettersetter方法的類吝羞。
數(shù)據(jù)類型支持解構(gòu)始鱼,從而可以實現(xiàn)返回多個值的函數(shù)。

數(shù)據(jù)類需要滿足如下要求:

  1. 主構(gòu)造器中至少需要一個參數(shù)脆贵;
  2. 主構(gòu)造器的所有參數(shù)需要使用 valvar 聲明為屬性;
  3. 不能使用 abstract起暮、open卖氨、sealed 修飾会烙,也不能定義成內(nèi)部類;
  4. 可以實現(xiàn)接口筒捺,也可繼承其他類柏腻。

數(shù)據(jù)類會自動生成如下內(nèi)容:

  1. 生成 equals()/hashCode() 方法;
  2. 自動重寫 toString() 方法系吭;
  3. 為每個屬性自動生成 operator 修飾的 componentN() 方法五嫂;
  4. 生成 copy() 方法,用于完成對象復制肯尺。

數(shù)據(jù)類定義

data class DataClass(
    val result: Int,
    val status: Int
)

數(shù)據(jù)類使用

fun main() {
    val (result, status) = DataClass(1, 2)
    println("result: $result, status: $status") //result: 1, status: 2
    val d1 = DataClass(1, 1)
    val d2 = d1.copy()
    println(d1) //DataClass(result=1, status=1)
    println(d2) //DataClass(result=1, status=1)
    println(d1 === d2) //false沃缘,說明 copy() 出來的不是同一個的對象
}

Kotlin 標準庫中提供了 Pair(支持兩個任意類型的屬性) 和 Triple(支持三個任意類型的屬性) 兩個數(shù)據(jù)類。


Lambda 表達式中解構(gòu)

如果 Lambda 表達式的參數(shù)是支持解構(gòu)的類型则吟,那么就可以在括號中引入多個新參數(shù)來替代單個參數(shù)槐臀。
map.mapValues { entry -> "${entry.value}" }
可以寫成
map.mapValues { (_, value) -> "$value" }

Lambda 表達式參數(shù)與解構(gòu)的區(qū)別:
{ a -> ... }:一個參數(shù)
{ a, b -> ... }:兩個參數(shù)
{ (a, b) -> ... }:一個參數(shù),并解構(gòu)成了兩個變量
{ (a, b), c -> ... }:兩個參數(shù)氓仲,第一次參數(shù)解構(gòu)成了兩個變量

注意:Lambda 表達式中的參數(shù)是不需要圓括號的水慨,如果出現(xiàn)圓括號,那就是使用解構(gòu)


屬性和字段

屬性是 Kotlin 中的一個重要特色敬扛,相當于 Java 中的field加上gettersetter方法(只讀屬性沒有setter方法)晰洒,且開發(fā)者不需要自己實現(xiàn)gettersetter
在定義 Kotlin 的普通屬性時啥箭,必須顯示指定初始值谍珊,要么在定義時指定,要么在構(gòu)造器中指定捉蚤。

// 屬性a需要在構(gòu)造器中初始化抬驴,屬性b,c直接在定義時初始化
// a缆巧,b是只讀屬性布持,只有g(shù)etter方法
// c是讀寫屬性,有g(shù)etter和setter方法
class Item(val a: String) {
    val b = "bbb"
    var c = "ccc"
}

在 Kotlin 類中定義屬性后陕悬,Kotlin 中只能使用點語法來訪問屬性题暖,Java 中只能使用 getter 和 setter 方法來訪問屬性。


自定義 getter 和 setter

雖然定義了屬性之后捉超,系統(tǒng)會自動生成gettersetter方法胧卤,但是你還可以自定義這兩個方法。無須使用 fun 關(guān)鍵字拼岳。
getterget() {}(可使用單表達式)枝誊,應該是一個無參,有返回值的方法惜纸;
setterset(value) {}(可使用單表達式)叶撒,應該帶一個參數(shù)绝骚,無返回值。

class UserInfo(var first: String, var last: String) {
    // 自定義getter和setter
    var fullName: String
        // 由于fullName是通過first和last計算出來的祠够,所以不需要生成field压汪,所以就不能設(shè)置初始值
        get() = "$first.$last"
        set(value) {
            if ("." !in value && value.indexOf(".") != value.lastIndexOf(".")) {
                throw IllegalArgumentException("您輸入的名稱不合法")
            } else {
                val names = value.split(".")
                first = names[0]
                last = names[1]
            }
        }
    // 可直接在getter和setter方法名前修改可見性和添加注解,并不修改默認實現(xiàn)
    var school = "清華大學"
        private set
        @Inject get
}

val user1 = UserInfo("張", "三")
println("first: ${user1.first}, last: ${user1.last}, full: ${user1.fullName}") //first: 張, last: 三, full: 張.三
val user2 = UserInfo("張", "三")
user2.fullName = "李.四"
println("first: ${user2.first}, last: ${user2.last}, full: ${user2.fullName}") //first: 李, last: 四, full: 李.四

幕后字段

當定義完屬性后古瓤,系統(tǒng)自動為屬性生成的field字段就成為幕后字段(backing field)止剖。
只要滿足以下條件,系統(tǒng)就會為屬性生成幕后字段:

  1. 該屬性使用系統(tǒng)自動生成的gettersetter落君。
  2. 重寫gettersetter時穿香,使用field顯式引用了幕后字段。
class BackingField(name: String, age: Int) {
    var name = name
        set(value) {
            if (value.length < 2 || value.length > 6) {
                println("您輸入的姓名不合法叽奥!")
            } else {
                field = value
            }
        }
    var age = age
        set(value) {
            if (value < 0 || value > 100) {
                println("您輸入的年齡不合法扔水!")
            } else {
                field = value
            }
        }
}

val backingField = BackingField("張三", 29)
backingField.name = "張三三三三三三"
println(backingField.name) //張三
backingField.name = "李四"
println(backingField.name) //李四

gettersetter方法中,需要通過field關(guān)鍵字來引用幕后字段朝氓。


幕后屬性

如果需要自定義field魔市,并自定義getter和setter,就可以使用幕后屬性(backing property)赵哲。
幕后屬性就是用private修飾的屬性待德,Kotlin不會為幕后屬性提供getter和setter方法。

class BackingProperty(name: String) {
    // 定義幕后屬性 _name
    private var _name: String = name
    // name賦值取值都是通過幕后屬性 _name 進行的
    var name
        get() = _name
        set(value) {
            _name = value
        }
}

val backingProperty = BackingProperty("Kotlin")
println(backingProperty.name) //Kotlin
backingProperty.name = "Java"
println(backingProperty.name) //Java

延遲初始化屬性

設(shè)置延遲初始化后枫夺,就可以在定義時和構(gòu)造方法里不設(shè)置初始值了将宪。使用lateinit關(guān)鍵字修飾。
lateinit修飾符有以下限制:

  1. 只能修飾在類體中聲明的可變屬性橡庞,即lateinit var是固定搭配较坛;
  2. 修飾的屬性不能有自定義的gettersetter方法;
  3. 修飾的屬性必須是非空類型扒最;
  4. 修飾的屬性不能是原生類型(即Java的8種類型對應的類型)丑勤。

注意:使用lateinit修飾后,Kotlin不會為屬性執(zhí)行默認初始化吧趣,如果在賦值之前調(diào)用法竞,則會引發(fā)lateinit property name has not been initialized異常。

class LateInit {
    lateinit var a: String
    lateinit var b: String
}

val lateInit = LateInit()
lateInit.a = "aaa"
lateInit.b = "bbb"
println("${lateInit.a}, ${lateInit.b}") //aaa, bbb

內(nèi)聯(lián)屬性

可以使用inline修飾符修飾沒有幕后字段的屬性的gettersetter方法强挫,也可以修飾屬性本身岔霸,這就相當于同時修飾該屬性的gettersetter
被修飾的gettersetter方法在調(diào)用時會執(zhí)行內(nèi)聯(lián)化俯渤。

class InlineProp {

    // 定義普通屬性呆细,由于有幕后字段,故不能被inline修飾
    var name: String = ""

    // inline get八匠,不能有幕后字段field
    val firstName: String
        inline get() = name.split(".")[0]

    // inline set絮爷,不能有幕后字段field
    var lastName: String
        inline set(value) {
            name = "${name.split(".")[0]}.$value"
        }
        get() = name.split(".")[1]

    // inline prop <=> inline get & set诡曙,不能有幕后字段field
    inline var userName: String
        get() = name
        set(value) {
            if ("." !in value && value.indexOf(".") != value.lastIndexOf(".")) {
                println("您輸入的名稱不合法")
                return
            }
            name = value
        }
}

深入構(gòu)造器

Kotlin 類可以定義0 ~ 1個主構(gòu)造器和0 ~ N個次構(gòu)造器。
如果主構(gòu)造器沒有任何注解或可見性修飾符略水,則可以省略constructor關(guān)鍵字

主構(gòu)造器和初始化塊

主構(gòu)造器的作用:
初始化塊可以使用主構(gòu)造器定義的形參;
在聲明屬性時可以使用主構(gòu)造器定義的形參劝萤;

class ConstructorTest(name: String) {
    // 初始化塊中可以直接調(diào)用主構(gòu)造器中定義的參數(shù)
    init {
        println(name)
    }
}

// 定義一個private的主構(gòu)造器渊涝,不可省略constructor關(guān)鍵字
class ConstructorTest private constructor(name: String) {
    // 初始化塊中可以直接調(diào)用主構(gòu)造器中定義的參數(shù)
    init {
        println(name)
    }
}

次構(gòu)造器和構(gòu)造器重載

初始化塊必定在每個構(gòu)造器之前調(diào)用,因為次構(gòu)造器是委托的主構(gòu)造器床嫌,即委托調(diào)用初始化塊跨释。
: this()

// 定義一個無參的主構(gòu)造器
class ConstructorOverload() {
    var a: String = ""
    var b: String = ""
    init {
        println("這是初始化塊")
    }

    // 構(gòu)造器重載,定義有一個參數(shù)的次構(gòu)造器厌处,委托主構(gòu)造器鳖谈,即委托調(diào)用初始化塊,使用 : this()
    constructor(a: String): this() {
        println("有一個參數(shù)的構(gòu)造器:$a")
        this.a = a
    }

    // 構(gòu)造器重載阔涉,定義有兩個參數(shù)的次構(gòu)造器缆娃,委托主構(gòu)造器,即委托調(diào)用初始化塊瑰排,使用 : this()
    constructor(a: String, b: String): this() {
        println("有兩個參數(shù)的構(gòu)造器:a = $a贯要,b = $b")
        this.a = a
        this.b = b
    }
}

val constructorOverload = ConstructorOverload()
//這是初始化塊
val constructorOverload1 = ConstructorOverload("param1")
//這是初始化塊
//有一個參數(shù)的構(gòu)造器:param1
val constructorOverload2 = ConstructorOverload("param1", "param2")
//這是初始化塊
//有兩個參數(shù)的構(gòu)造器:a = param1,b = param2

主構(gòu)造器聲明屬性

在主構(gòu)造器參數(shù)上直接加上 var 或 val 即可聲明屬性椭住,也可為參數(shù)設(shè)上默認值

// 在主構(gòu)造器參數(shù)上直接加上 var 或 val 即可聲明屬性崇渗,也可為參數(shù)設(shè)上默認值
class ConstructorParam(var p1: String = "p1", var p2: String = "p2") {}

繼承

修飾符 class SubClass: SuperClass { ... }
Kotlin 的類默認是final的,不能派生子類京郑,所以如果需要讓一個類能派生子類宅广,需要使用open修飾該類。

open class SuperClass(name: String) {
    constructor(): this("nnnn")

    init {
        println(name)
    }
}

// 定義一個無參子類些举,必須立即調(diào)用父類構(gòu)造器
class SubClass1: SuperClass("foo") {
}

// 定義一個參數(shù)的子類跟狱,必須立即調(diào)用父類構(gòu)造器
class SubClass2(name: String): SuperClass(name) {
}

class SubClass3: SuperClass {
    // 定義一個次構(gòu)造器,隱式委托調(diào)用父類無參的構(gòu)造器
    constructor()

    // 定義一個參數(shù)的次構(gòu)造器金拒,顯式委托父類帶參數(shù)的構(gòu)造器
    constructor(name: String): super(name)

    // 定義兩個參數(shù)的次構(gòu)造器兽肤,顯式委托本類帶參數(shù)的構(gòu)造器
    constructor(name: String, name1: String): this(name)
}

重寫父類的方法

方法也需要使用open來修飾,才可以被子類重寫绪抛。
子類重寫父類的方法必須使用override來修飾资铡;

open class Bird(name: String) {
    init {
        println(name)
    }

    // 該方法可被子類重寫,故需要使用 open 修飾
    open fun fly() {
        println("我能飛")
    }
}

// 麻雀
class Sparrow : Bird("麻雀")

// 鴕鳥
class Ostrich : Bird("鴕鳥") {
    // 重寫父類的 fly 方法
    override fun fly() {
        println("我不能飛")
    }
}

val sparrow = Sparrow() //麻雀
sparrow.fly() //我能飛
val ostrich = Ostrich() //鴕鳥
ostrich.fly() //我不能飛

重寫父類的屬性

父類中需要被重寫的屬性幢码,也需要用open修飾笤休;
子類重寫屬性必須用override修飾;
屬性重寫有兩個限制:

  1. 類型要兼容症副;
  2. 訪問權(quán)限要更大或相等店雅;只讀屬性val可被讀寫屬性var重寫政基;讀寫屬性var不可被只讀屬性val重寫;
open class Book {
    internal open var price: Double = 10.9
    open var publisher: String = ""
    open val name: String = ""
}

class KotlinBook: Book() {
    // 重寫父類price屬性闹啦,可擴大訪問權(quán)限
    public override var price: Double = 20.9
    // 重寫父類publisher屬性沮明,不能將var改成val,讀寫屬性不能被只讀屬性重寫
    override var publisher: String = "機械工業(yè)出版社"
    // 重寫父類name屬性窍奋,能將val改成var荐健,只讀屬性能被讀寫屬性重寫
    override val name: String = "Kotlin編程實踐"
}

val kotlinBook = KotlinBook()
println("《${kotlinBook.name}》是由“${kotlinBook.publisher}”出版,售價${kotlinBook.price}元") //《Kotlin編程實踐》是由“機械工業(yè)出版社”出版琳袄,售價20.9元

super

訪問被子類重寫的屬性或調(diào)用被子類重寫的方法時江场,默認會訪問子類中的屬性或執(zhí)行子類中的方法,若仍想訪問父類中被重寫的屬性或調(diào)用父類中被重寫的方法窖逗,需要使用super址否。

open class Book {
    internal open var price: Double = 10.9
    open var publisher: String = "出版社"
    open val name: String = "書名"

    open fun test1() {
        println("Book test1")
    }

    open fun test2() {
        println("Book test2")
    }
}

class KotlinBook: Book() {
    // 重寫父類price屬性,可擴大訪問權(quán)限
    public override var price: Double = 20.9
    // 重寫父類publisher屬性碎紊,不能將var改成val佑附,讀寫屬性不能被只讀屬性重寫
    override var publisher: String = "機械工業(yè)出版社"
    // 重寫父類name屬性,能將val改成var矮慕,只讀屬性能被讀寫屬性重寫
    override val name: String = "Kotlin編程實踐"

    // 訪問被重寫的屬性帮匾,默認只會訪問當前子類中定義的屬性
    fun getSelfName() = name
    // 如果想訪問父類中的屬性,使用super
    fun getParentName() = super.name

    override fun test2() {
        println("KotlinBook test2")
    }

    fun test3() {
        // test2 被當前子類重寫痴鳄,默認子類的test2
        test2() //KotlinBook test2
        // 使用super來調(diào)用父類的test2
        super.test2() //Book test2
        // 由于當前子類未重寫test1瘟斜,故會調(diào)用父類的test1
        test1() //Book test1
    }
}

強制重寫

如果子類從多個直接超類型(接口或類)繼承了同名成員,那么Kotlin要求子類必須重寫該成員痪寻;
如果要訪問超類中的成員螺句,可使用super<超類型名>來進行引用。

open class MandatoryOverride {
    open fun test() {
        println("class MandatoryOverride test")
    }
}

interface IMandatoryOverride {
    fun test() {
        println("interface IMandatoryOverride test")
    }
}

class Mandatory: MandatoryOverride(), IMandatoryOverride {
    // 由于MandatoryOverride和IMandatoryOverride中都有test方法橡类,所以子類必須強制重寫該方法
    override fun test() {
        // 可使用super<超類型名>來引用指定超類的test方法
        super<MandatoryOverride>.test() //class MandatoryOverride test
        super<IMandatoryOverride>.test() //interface IMandatoryOverride test
    }
}

多態(tài)

把一個子類對象賦值給父類變量蛇尚,這就是多態(tài)。
變量在編譯階段只能調(diào)用其編譯時類型所具有的方法顾画,但在運行時則執(zhí)行其運行時所具有的方法取劫。

open class BaseClass {
    open var book = 6

    fun base() {
        println("父類中的普通方法")
    }

    open fun test() {
        println("父類中可以被覆蓋的方法")
    }
}

class SubClass: BaseClass() {
    override var book = 60

    fun sub() {
        println("子類中的普通方法")
    }

    override fun test() {
        println("子類的覆蓋父類的方法")
    }
}

//把一個子類對象賦值給父類變量,這就是多態(tài)
val baseClass: BaseClass = SubClass()
println(baseClass.book) //60
baseClass.base() //父類中的普通方法
baseClass.test() //子類的覆蓋父類的方法
// baseClass.sub() 由于聲明的是BaseClass研侣,沒有sub方法谱邪,故此處使用會編譯錯誤

使用is檢查類型

Kotlin提供了類型檢查運算符is!is,來保證類型轉(zhuǎn)換不會出錯庶诡。

is運算符前面操作數(shù)的編譯時類型要么與后面的類相同惦银,要么與后面的類具有父子繼承關(guān)系,否則編譯時程序就會報錯。

val hello: Any = "Hello"
//由于Any是所有類的基類扯俱,所以可以使用 is String书蚪,is Date
println("hello 是String:${hello is String}") //hello 是String:true
println("hello 是Date:${hello is Date}") //hello 是Date:false
val str = "Hello"
// println(str is Date) 編譯錯誤,因為String與Date沒有繼承關(guān)系

Kotlin的is!is是非常智能的迅栅,只要你對其進行了判斷殊校,變量就會自動轉(zhuǎn)換為目標類型。

val hello: Any = "Hello"
if (hello is String) {
    println(hello.length) //hello自動轉(zhuǎn)換為String读存,可直接調(diào)用String相關(guān)的方法箩艺。
}

when分支也可進行智能轉(zhuǎn)換。

fun isTest(x: Any) {
    when (x) {
        is String -> println(x.length)
        is Int -> println(x.toDouble())
    }
}

isTest(3) //3.0
isTest("abcd") //4

使用as運算符轉(zhuǎn)型

除了使用is進行類型檢查宪萄,還可使用asas?進行強制轉(zhuǎn)型。
as:不安全的強制轉(zhuǎn)型運算符榨惰,若轉(zhuǎn)換失敗拜英,會引發(fā)ClassCastException異常;
as?:安全的強制轉(zhuǎn)型運算符琅催,若轉(zhuǎn)換失敗居凶,不會引發(fā)異常,而是返回null藤抡。

val obj: Any = "Hello"
//使用as強制轉(zhuǎn)型侠碧,成功
val objStr = obj as String
println(objStr)
// val objInt = obj as Int 轉(zhuǎn)型失敗,會引發(fā)ClassCastException異常
// val num: Number = objStr as Number 由于objStr是String缠黍,String和Number沒有繼承關(guān)系弄兜,所以編譯器會提示轉(zhuǎn)換不可能成功

val objStrNullable = obj as? String
println(objStrNullable?.length) //5
val objIntNullable = obj as? Int
println(objIntNullable?.toDouble()) //null
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市瓷式,隨后出現(xiàn)的幾起案子替饿,更是在濱河造成了極大的恐慌,老刑警劉巖贸典,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件视卢,死亡現(xiàn)場離奇詭異,居然都是意外死亡廊驼,警方通過查閱死者的電腦和手機据过,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來妒挎,“玉大人绳锅,你說我怎么就攤上這事〖⒙” “怎么了榨呆?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我积蜻,道長闯割,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任竿拆,我火速辦了婚禮宙拉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘丙笋。我一直安慰自己谢澈,他們只是感情好,可當我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布御板。 她就那樣靜靜地躺著锥忿,像睡著了一般。 火紅的嫁衣襯著肌膚如雪怠肋。 梳的紋絲不亂的頭發(fā)上敬鬓,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天,我揣著相機與錄音笙各,去河邊找鬼钉答。 笑死,一個胖子當著我的面吹牛杈抢,可吹牛的內(nèi)容都是我干的数尿。 我是一名探鬼主播,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼惶楼,長吁一口氣:“原來是場噩夢啊……” “哼右蹦!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起歼捐,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤嫩实,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后窥岩,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體甲献,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年颂翼,在試婚紗的時候發(fā)現(xiàn)自己被綠了晃洒。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡朦乏,死狀恐怖球及,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情呻疹,我是刑警寧澤吃引,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響镊尺,放射性物質(zhì)發(fā)生泄漏朦佩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一庐氮、第九天 我趴在偏房一處隱蔽的房頂上張望语稠。 院中可真熱鬧,春花似錦弄砍、人聲如沸仙畦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽慨畸。三九已至,卻和暖如春衣式,著一層夾襖步出監(jiān)牢的瞬間先口,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工瞳收, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人厢汹。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓螟深,卻偏偏與公主長得像,于是被迫代替她去往敵國和親烫葬。 傳聞我的和親對象是個殘疾皇子界弧,可洞房花燭夜當晚...
    茶點故事閱讀 44,611評論 2 353