Kotlin 知識梳理(13) - 運(yùn)行時的泛型

Kotlin 知識梳理系列文章

Kotlin 知識梳理(1) - Kotlin 基礎(chǔ)
Kotlin 知識梳理(2) - 函數(shù)的定義與調(diào)用
Kotlin 知識梳理(3) - 類、對象和接口
Kotlin 知識梳理(4) - 數(shù)據(jù)類、類委托 及 object 關(guān)鍵字
Kotlin 知識梳理(5) - lambda 表達(dá)式和成員引用
Kotlin 知識梳理(6) - Kotlin 的可空性
Kotlin 知識梳理(7) - Kotlin 的類型系統(tǒng)
Kotlin 知識梳理(8) - 運(yùn)算符重載及其他約定
Kotlin 知識梳理(9) - 委托屬性
Kotlin 知識梳理(10) - 高階函數(shù):Lambda 作為形參或返回值
Kotlin 知識梳理(11) - 內(nèi)聯(lián)函數(shù)
Kotlin 知識梳理(12) - 泛型類型參數(shù)


一铲掐、本文概要

本文是對<<Kotlin in Action>>的學(xué)習(xí)筆記,如果需要運(yùn)行相應(yīng)的代碼可以訪問在線環(huán)境 try.kotlinlang.org密强,這部分的思維導(dǎo)圖為:

二短蜕、運(yùn)行時的泛型:擦除和實化類型參數(shù)

2.1 運(yùn)行時的泛型

Java一樣凶伙,Kotlin的泛型在運(yùn)行時也被擦除了,這意味著 泛型類實例不會攜帶用于創(chuàng)建它的類型實參的信息冲秽。

例如舍咖,如果你創(chuàng)建了一個List<String>矩父,在運(yùn)行時你只能看到它是一個List锉桑,不能識別出列表本打算包含的是String類型的元素。

接下來我們談?wù)劙殡S著擦除類型信息的約束窍株,因為類型實參String沒有被存儲下來民轴,你不能檢查它們。例如球订,你不能判斷一個列表是一個包含字符串的列表還是包含其它對象的列表后裸,也就是說,在is檢查中不可能使用類型實參中的類型冒滩,例如

fun main(args: Array<String>) {
    val authors = listOf("first", "second")
    if (authors is List<Int>) {}
}

將會在編譯時拋出下面的異常:

>> Cannot check for instance of erased type

Kotlin不允許使用 沒有指定類型實參的泛型類型微驶,如果希望檢查一個值是否是列表,而不是set或者其它對象开睡,可以使用特殊的 星號投影 語法來做這個檢查:

if (value is List<*>)

實際上因苹,泛型類型擁有的每個類型形參都需要一個*,現(xiàn)在你可以認(rèn)為它就是 擁有未知類型實參的泛型類型篇恒。

asas?轉(zhuǎn)換中仍然可以使用一般的泛型類型扶檐,但是如果該類 有正確的基礎(chǔ)類型但類型實參是錯誤的,轉(zhuǎn)換也不會失敗胁艰,因為在運(yùn)行時轉(zhuǎn)換發(fā)生的時候類型實參是未知的款筑。因此,這樣的轉(zhuǎn)換會導(dǎo)致編譯器發(fā)出unchecked cast的警告腾么,例如下面這段程序:

fun printSum(c: Collection<*>) {
    val intList = c as? List<Int>
            ?: throw IllegalArgumentException("List is expected")
    println(intList.sum())
}

fun main(args: Array<String>) {
    //(1) 正常運(yùn)行奈梳。
    printSum(listOf(1, 2, 3))
    //(2) as 檢查是成功的,但是調(diào)用 intList.sum() 方法時會拋出異常解虱。
    printSum(listOf("a", "b", "c"))
}

(2)調(diào)用時攘须,并不會拋出IllegalArgumentException異常,而是在調(diào)用sum函數(shù)時才發(fā)生饭寺,因為sum函數(shù)試著從列表中讀取Number值然后把它們加在一起阻课,把String當(dāng)做Number使用的嘗試會導(dǎo)致運(yùn)行時的ClassCastException

假如在編譯期艰匙,Kotlin已經(jīng)知道了相應(yīng)的類型信息限煞,那么is檢查是允許的:

fun printSum(c: Collection<Int>) {
    if (c is List<Int>) {
        println(c.sum())
    }
}

fun main(args: Array<String>) {
    printSum(listOf(1, 2, 3))
}

c是否擁有類型List<Int>的檢查是可行的,因為我們將函數(shù)類型的形參類型聲明為了Collection<Int>员凝,因此編譯期就確定了集合包含的是整型數(shù)字署驻。

不過,Kotlin有特殊的語法結(jié)構(gòu)可以允許你 在函數(shù)體中使用具體的類型實參,但只有inline函數(shù)可以旺上,接下來讓我們來看看這個特性瓶蚂。

2.2 聲明帶實化類型參數(shù)的函數(shù)

Kotlin泛型在運(yùn)行時會被擦除,這意味著如果你有一個泛型類的實例宣吱,你無法弄清楚在這個實例創(chuàng)建時用的究竟是哪些類型實參窃这。泛型函數(shù)的實參類型也是這樣,在調(diào)用泛型函數(shù)的時候征候,在函數(shù)體中你不能決定調(diào)用它用的類型實參杭攻。

//將會在編譯時拋出 "Cannot check for instance of erased type : T" 的異常
fun <T> isA(value : Any) = value is T

內(nèi)聯(lián)函數(shù)的類型形參能夠被實化

只有一種例外可以避免這種限制:內(nèi)聯(lián)函數(shù)。內(nèi)聯(lián)函數(shù)的類型形參能夠被實化疤坝,意味著你可以 在運(yùn)行時引用實際的類型實參兆解。前面我們介紹過內(nèi)聯(lián)函數(shù)的兩個優(yōu)點(diǎn):

  • 編譯器會把每一次函數(shù)調(diào)用都替換成函數(shù)實際的代碼實現(xiàn)
  • 如果該函數(shù)使用了lambdalambda的代碼也會內(nèi)聯(lián)跑揉,所以不會創(chuàng)建匿名類

這里锅睛,我們介紹它一個新的優(yōu)點(diǎn):對于泛型函數(shù)來說,它們的類型參數(shù)可以被實化历谍。我們將方面的函數(shù)修改如下现拒,聲明為inline并且用reified標(biāo)記類型參數(shù),就能用該函數(shù)檢查value是不是T的實例:

inline fun <reified T> isA(value: Any) = value is T

fun main(args: Array<String>) {
    println(isA<String>("abc"))
    println(isA<String>(123))
}

運(yùn)行結(jié)果為:

>> true
>> false

filterIsIntance函數(shù)可以接收一個集合扮饶,選擇其中那些指定類的實例具练,然后返回這些被選中的實例:

fun main(args: Array<String>) {
    val items = listOf("one", 2, "three")
    println(items.filterIsInstance<String>())
}

運(yùn)行結(jié)果為:

[one, three]

該函數(shù)的簡化實現(xiàn)為:

inline fun <reified T> Iterable<*>.filterIsIntance() : List<T> {
    val destination = mutableListOf<T>()
    for (element in this) {
        if (element is T) {
            destination.add(element)
        }
    }
}

為什么實化只對內(nèi)聯(lián)函數(shù)有效

我們之所以可以在inline函數(shù)中使用element is T這樣的判斷,而不能在普通的類或函數(shù)中執(zhí)行的原因是因為:編譯器把 實現(xiàn)內(nèi)聯(lián)函數(shù)的字節(jié)碼 插入每一次調(diào)用發(fā)生的地方甜无,每次你 調(diào)用帶實化類型參數(shù)的函數(shù) 時扛点,編譯器都知道這次特定調(diào)用中 用作類型實參的確切類型,因此岂丘,編譯器可以生成 引用作為類型實參的具體類 的字節(jié)碼陵究。

因為生成的字節(jié)碼引用了具體類,而不是類型參數(shù)奥帘,它不會被運(yùn)行時發(fā)生類型擦除铜邮。注意,帶reified類型參數(shù)的inline函數(shù)不能在Java代碼中調(diào)用寨蹋,普通的內(nèi)聯(lián)函數(shù)可以像常規(guī)函數(shù)那樣在Java中調(diào)用 - 它們可以被調(diào)用而不能被內(nèi)聯(lián)松蒜。帶實化類型參數(shù)的函數(shù)需要額外的處理,來把類型實參的值替換到字節(jié)碼中已旧,所以它們必須永遠(yuǎn)是內(nèi)聯(lián)的秸苗,這樣它們不可能用Java那樣普通的方式調(diào)用。

2.3 使用實化類型參數(shù)代替類引用

另一種實化類型參數(shù)的常見使用場景是接收java.lang.Class類型參數(shù)的API構(gòu)建適配器运褪。例如JDK中的ServiceLoader惊楼,它接收一個代表接口或抽象類的java.lang.Class玖瘸,并返回實現(xiàn)了該接口的實例。

val serviceImpl = ServiceLoader.load(Service::class.java)

::class.java的語法展現(xiàn)了如何獲取java.lang.Class對應(yīng)的Kotlin類檀咙,這和Java中的Service.Class是完全等同的雅倒,現(xiàn)在我們用 帶實化類型參數(shù)的函數(shù) 重寫這個例子:

val serviceImpl = loadService<String>()

loadService的定義為如下,要加載的服務(wù)類 現(xiàn)在被指定成了loadService 函數(shù)的類型實參

inline fun <reified T> loadService() {
    //把 "T::class" 當(dāng)成類型形參的類訪問弧可。
    return ServiceLoader.load(T::class.java)
}

這種用在普通類上的::class.java語法也可以同樣用在實化類型參數(shù)上蔑匣,使用這種語法會產(chǎn)生對應(yīng)到指定為類型參數(shù)的類的java.lang.Class,你可以正常地使用它侣诺,最后我們以一個startActivity的調(diào)用來結(jié)束本節(jié)的討論:

inline fun <reified T : Activity> Context.startActivity {
    val intent = new Intent(this, T::class.java)
    startActivity(intent)
}

>> startActivity<DetailActivity>()

2.4 實化類型參數(shù)的限制

我們可以按下面的方式來使用實化類型參數(shù)

  • 用在類型檢查和類型轉(zhuǎn)換中:is殖演、!isas年鸳、as?
  • 使用Kotlin反射API::class
  • 獲取對應(yīng)的java.lang.Class丸相,::class.java
  • 作為調(diào)用其它函數(shù)的類型實參

不能做下面的事情:

  • 創(chuàng)建指定為類型參數(shù)的類的實例
  • 調(diào)用類型參數(shù)類的伴生對象的方法
  • 調(diào)用 帶實化類型參數(shù)函數(shù) 的時候使用 非實化類型形參作為類型實參
  • 把類搔确、屬性或者非內(nèi)聯(lián)函數(shù)的類型參數(shù)標(biāo)記為reified,因為實化類型參數(shù)只能用在內(nèi)聯(lián)函數(shù)上灭忠,使用實化類型參數(shù)意味著函數(shù)和所有傳給它的lambda都會被內(nèi)聯(lián)膳算,如果內(nèi)聯(lián)函數(shù)使用lambda的方法導(dǎo)致lambda不能被內(nèi)聯(lián),或者你不想lambda因為性能的關(guān)系被內(nèi)聯(lián)弛作,可以使用noinline修飾符涕蜂。

三、變型:泛型和子類型化

變型的概念描述了擁有 相同基礎(chǔ)類型不同類型實參 的類型之間是如何關(guān)聯(lián)的映琳,例如List<String>List<Any>之間如何關(guān)聯(lián)机隙。

3.1 為什么存在變型:給函數(shù)傳遞實參

假設(shè)你有一個接受List<Any>作為實參的函數(shù),那么把List<String>類型的變量傳遞給這個函數(shù)是否安全呢萨西?我們來看下面兩個例子:

  • 第一個例子
fun printContents(list: List<Any>) {
    println(list.joinToString())
}

fun main(args: Array<String>) {
    printContents(listOf("abc", "bac"))
}

這上面的函數(shù)可以正常地工作有鹿,函數(shù)把每個元素都當(dāng)作Any對待,而且因為每個字符都是Any谎脯,因此這是完全安全的葱跋,運(yùn)行結(jié)果為:

>> abc, bac
  • 第二個例子,與之前不同源梭,它會修改列表:
fun addAnswer(list : MutableList<Any>) {
    list.add(42)
}

fun main(args: Array<String>) {
    val strings = mutableListOf("abc", "bac")
    addAnswer(strings)
}

這里聲明了一個類型為MutableList<String>的變量strings娱俺,然后嘗試把它傳遞給一個接收MutableList<Any>的函數(shù),編譯器將不會通過調(diào)用废麻。

因此荠卷,當(dāng)我們將一個字符串列表傳遞給期望Any對象的列表時,如果 函數(shù)添加或者替換了 列表中的元素(通過MutableList來推斷)就是不安全的脑溢,因為這樣會產(chǎn)生類型不一致的可能僵朗,否則它就是安全的赖欣。

3.2 類、類型和子類型

變量的類型 規(guī)定了 變量的可能值验庙,有時候我們會把類型和類當(dāng)成同樣的概念使用顶吮,但它們不一樣。

類粪薛、類型

非泛型類

對于非泛型類來說悴了,類的名稱可以直接當(dāng)作類型使用。例如违寿,var x : String聲明了一個可以保存String類的實例的變量湃交,而var x : String?聲明了它的可空類型版本,這意味著 一個Kotlin類都可以用于構(gòu)造至少兩種類型藤巢。

泛型類

要得到一個合法的類型搞莺,需要首先得到一個泛型類您没,并用一個作為 類型實參的具體類型 替換泛型類的 類型形參泞当。

List是一個類而不是類型,下面列舉出來的所有替代品都是合法的類型:List<Int>集歇、List<String?>List<List<String>>绍刮,每一個 泛型類都可能生成潛在的無限數(shù)量的類型温圆。

子類型

子類型的含義為:

任何時候如果需要的是類型A的值,能夠使用類型B的值當(dāng)做A的值孩革,類型B就稱為類型A的子類型岁歉。

例如IntNumber的子類型,但Int不是String的子類型膝蜈,這個定義還表明了任何類型都可以被認(rèn)為是它自己的子類型锅移。

超類型

超類型子類型 的反義詞

如果AB的子類型,那么B就是A的超類型彬檀。

編譯器在每一次給變量賦值或者給函數(shù)傳遞實參的時候都要做這項檢查:

  • 只有 值的類型變量類型的子類型 時帆啃,才允許存儲變量的值
  • 只有當(dāng) 表達(dá)式的類型函數(shù)參數(shù)的類型的子類型 時,才允許把該表達(dá)式傳給函數(shù)

子類窍帝、子類型

在簡單情況下努潘,子類和子類型本質(zhì)上是一樣的,例如Int類是Number的子類坤学,因此Int類型是Number類型的子類型疯坤。

一個非空類型是它的可空版本的子類型,但它們都對應(yīng)著同一個類深浮,你始終能夠在可空類型的變量中存儲非空類型值压怠。

當(dāng)開始涉及泛型類時,子類型和子類之間的差異就顯得格外重要飞苇。正如我們上面見到的菌瘫,MutableList<String>不是MutableList<Any>的子類型蜗顽。

對于泛型類MutableList而言,無論AB是什么關(guān)系雨让,MutableList<A>既不是MutableList<B>的子類型也不是它的超類型雇盖,它就被稱為 在該類型參數(shù)上是不變型的

Java中的所有類都是不變型的栖忠。在前一節(jié)中崔挖,我們見到了List類,對它來說庵寞,子類型化規(guī)則不一樣狸相,Kotlin中的List接口表示的是只讀集合。如果AB的子類型捐川,那么List<A>就是List<B>的子類型脓鹃,這樣的類或者接口被稱為 協(xié)變的

3.3 協(xié)變:保留子類型化關(guān)系

一個協(xié)變類是一個泛型類属拾,如果AB的子類型将谊,那么Producer<A>就是Producer<B>的子類型,我們說 子類型化被保留了渐白。

Kotlin中,要聲明類在某個類型參數(shù)上是可以協(xié)變的逞频,在該類型參數(shù)的名稱前加上out關(guān)鍵字即可纯衍,下面例子就可以表達(dá)為:Producer類在類型參數(shù)T上是可以協(xié)變的。

interface Producer<out T> {
    fun produce() : T
}

將一個類的類型參數(shù)標(biāo)記為協(xié)變的苗胀,在 該類型實參沒有精確匹配到函數(shù)中定義的類型形參時襟诸,可以讓該類的值作為這些函數(shù)的實參傳遞,也可以作為這些函數(shù)的返回值基协。

你不能把任何類都變成協(xié)變的歌亲,這樣不安全。讓類在某個類型參數(shù)變?yōu)閰f(xié)變澜驮,限制了該類中對該類型參數(shù)使用 的可能性陷揪,要保證類型安全,你只能用在所謂的out位置杂穷,意味著這個類 只能生產(chǎn)類型T的值而不能消費(fèi)它們悍缠。

在類成員的聲明中類型參數(shù)的使用分為inout位置,考慮這樣一個類耐量,它聲明了一個類型參數(shù)T并包含了一個使用T的函數(shù):

  • 如果函數(shù)把T當(dāng)成返回類型飞蚓,我們說它在out位置,這種情況下廊蜒,該函數(shù)生產(chǎn)類型為T的值
  • 如果T用作函數(shù)參數(shù)的類型趴拧,它就在in的位置溅漾,這樣函數(shù)消費(fèi)類型為T的值。

因此類型參數(shù)T上的關(guān)鍵字有兩層含義:

  • 子類型化會被保留著榴,即前面談到的Producer<Cat>Producer<Animal>的子類型
  • T只能用在out位置

在構(gòu)造方法的參數(shù)上使用 out

構(gòu)造方法的參數(shù)既不在in位置添履,也不再out位置,即使類型參數(shù)聲明成了out兄渺,仍然可以在構(gòu)造方法參數(shù)的聲明中使用它缝龄。

class Herd<out T : Animal> (vararg animals : T) { ... }

如果把類的實例當(dāng)成一個更泛化的類型的實例使用,變型會防止該實例被誤用挂谍,不能調(diào)用存在潛在危險的方法叔壤。構(gòu)造方法不是那種在實例創(chuàng)建之后還能調(diào)用的方法,因此它不會有潛在的危險口叙。

然而炼绘,如果你在構(gòu)造方法的參數(shù)上使用了關(guān)鍵字varval,同時就會聲明一個gettersetter妄田,因此俺亮,對只讀屬性來說,類型參數(shù)用在了out位置疟呐,而可變屬性在outin位置都使用了它脚曾。

class Herd<T : Animal> (var leadAnimal : T, vararg animals : T) { ... }

上面這個例子中,T不能用out標(biāo)記启具,因為類包含屬性leadAnimalsetter本讥,它在in位置用到了T

位置規(guī)則只覆蓋了類外部可見的 API

位置規(guī)則只覆蓋了類外部可見的api鲁冯,私有方法的參數(shù)既不在in位置拷沸,也不在out位置,變型規(guī)則只會防止外部使用者對類的誤用薯演,但不會對類自己的實現(xiàn)起作用撞芍。

class Herd<out T : Animal> (private var leadAnimal : T, vararg animals : T) { ... }

現(xiàn)在可以安全地讓HerdT上協(xié)變,因為屬性leadAnimal被聲明成了私有跨扮。

3.4 逆變:反轉(zhuǎn)子類型化關(guān)系

逆變的概念可以看成是協(xié)變的鏡像序无,對一個逆變類來說,它的子類型化關(guān)系與用作類型實參的類的子類型化關(guān)系是相反的:如果BA的子類型好港,那么Consumer<A>就是Consumer<B>的子類型愉镰。

Comparator接口為例,這個接口定義了一個compare方法钧汹,用于比較兩個指定的對象:

interface Comparator<in T> {
    fun compare(e1 : T, e2 : T) : Int { ... }
}

這個接口方法只是消費(fèi)類型為T的值丈探,這說明T只在in位置使用,因此它的聲明之前用了in關(guān)鍵字拔莱。

一個為特定類型的值定義的比較器顯然可以比較該類型任意子類型的值碗降,例如隘竭,如果有一個Comparator<Any>,可以用它比較任意具體類型的值讼渊。

val anyComparator = Comparator<Any> { e1, e2 -> e1.hashCode() - e2.hashCode() }
val strings : List<String> = ...
strings.sortedWith(anyComparator)

sortedWith期望一個Comparator<String>动看,傳給它一個能比較更一般的類型的比較器是安全的。如果你要在特定類型的對象上執(zhí)行比較爪幻,可以使用能處理該類型或者它的超類型的比較器菱皆。

這說明Comparator<Any>Comparator<String>的子類型,其中AnyString的超類型挨稿。不同類型之間的子類型關(guān)系這些類型的比較器之間的子類型關(guān)系 截然相反仇轻。

in關(guān)鍵字的意思是,對應(yīng)類型的值是傳遞進(jìn)來給這個類的方法的奶甘,并且被這些方法消費(fèi)篷店。和協(xié)變的情況類似,約束類型參數(shù)的使用將導(dǎo)致特定的子類型化關(guān)系臭家。

一個類可以在一個類型參數(shù)上協(xié)變疲陕,同時在另外一個類型參數(shù)上逆變。Function接口就是一個經(jīng)典的例子:

interface Function1<in P, out R> {
    operator fun invoke(p : P) : R
}

這意味著對這個函數(shù)類型的第一類型參數(shù)來說钉赁,子類型化反轉(zhuǎn)了蹄殃,而對于第二個類型參數(shù)來說,子類型化保留了你踩。例如窃爷,你有一個高階函數(shù),該函數(shù)嘗試對你所有的貓進(jìn)行迭代姓蜂,你可以把一個接收動物的lambda傳遞給它。

fun enumerate(f : (Cat) -> Number) { ... }
fun Animal.getIndex() : Int = ...

>> enumerate(Animal :: getIndex)

更多文章医吊,歡迎訪問我的 Android 知識梳理系列:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末钱慢,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子卿堂,更是在濱河造成了極大的恐慌束莫,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件草描,死亡現(xiàn)場離奇詭異览绿,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)穗慕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進(jìn)店門饿敲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人逛绵,你說我怎么就攤上這事怀各【缶拢” “怎么了?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵瓢对,是天一觀的道長寿酌。 經(jīng)常有香客問我,道長硕蛹,這世上最難降的妖魔是什么醇疼? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮法焰,結(jié)果婚禮上秧荆,老公的妹妹穿的比我還像新娘。我一直安慰自己壶栋,他們只是感情好辰如,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著贵试,像睡著了一般琉兜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上毙玻,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天豌蟋,我揣著相機(jī)與錄音,去河邊找鬼桑滩。 笑死梧疲,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的运准。 我是一名探鬼主播幌氮,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼胁澳!你這毒婦竟也來了该互?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤韭畸,失蹤者是張志新(化名)和其女友劉穎宇智,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體胰丁,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡随橘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了锦庸。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片机蔗。...
    茶點(diǎn)故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蜒车,到底是詐尸還是另有隱情讳嘱,我是刑警寧澤,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布酿愧,位于F島的核電站沥潭,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏嬉挡。R本人自食惡果不足惜钝鸽,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望庞钢。 院中可真熱鬧拔恰,春花似錦、人聲如沸基括。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽风皿。三九已至河爹,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間桐款,已是汗流浹背咸这。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留魔眨,地道東北人媳维。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像遏暴,于是被迫代替她去往敵國和親侄刽。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評論 2 354

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