Effective Java-泛型

Java1.5版本中增加了泛型眷茁。在沒有泛型之前筷凤,從集合中讀取到的每一個(gè)對象都必須進(jìn)行轉(zhuǎn)換耸携。如果不小心插入了錯(cuò)誤類型的對象棵癣,在運(yùn)行時(shí)的轉(zhuǎn)換處理就會出錯(cuò)。有了泛型之后夺衍,可以告訴編譯器每個(gè)集合中可以接受哪些對象類型狈谊,編譯器自動為插入操作進(jìn)行轉(zhuǎn)換,并在編譯時(shí)告知是否插入了類型錯(cuò)誤的對象沟沙,使得程序更加安全的畴,代碼意圖也更加清楚。

編譯器進(jìn)行類型匹配與檢查尝胆,若對象類型錯(cuò)誤,編譯時(shí)即可發(fā)現(xiàn)錯(cuò)誤护桦,而非要等到運(yùn)行時(shí)含衔。

本章內(nèi)容導(dǎo)圖:

1.不要在新代碼中使用原生態(tài)類型

泛型類/接口:聲明中具有一個(gè)或者多個(gè)類型參數(shù)的類/接口
每種泛型定義一組參數(shù)化的類型,如List<String>,讀作字符串列表贪染,表示元素類型為String的列表缓呛。
每個(gè)泛型都定義一個(gè)原生態(tài)類型,即不帶任何實(shí)際類型參數(shù)的泛型名稱杭隙。如與List<E>相對應(yīng)的原生態(tài)類型就是List哟绊。
原生態(tài)類型沒有泛型在安全性表述性方面的優(yōu)勢,它的存在僅是為了兼容引入泛型之前的遺留代碼痰憎,不應(yīng)在新代碼中繼續(xù)使用票髓。

//使用原生態(tài)類型
private final List stamps = new ArrayList();
stamps.add( new Stamp() );
stamps.add( new Coin() ); //可以正常添加
Stamp stamp = (Stamp)stamps.get(1); //運(yùn)行時(shí)錯(cuò)誤,拋出ClassCastException铣耘。

//使用泛型
private final List<Stamp> stamps = new ArrayList<Stamp>();
stamps.add( new Stamp() );
stamps.add( new Coin() ); //提示錯(cuò)誤洽沟,無法通過編譯
Stamp stamp = stamps.get(0); //使用時(shí)無需進(jìn)行手工轉(zhuǎn)換

由上述代碼可以看出,使用泛型的兩個(gè)好處為:
1.由編譯器確保插入正確的元素類型
2.從集合獲取元素時(shí)不再需要手工轉(zhuǎn)換了

如果要使用泛型蜗细,但不確定或不關(guān)心實(shí)際的類型參數(shù)裆操,可以使用一個(gè)?代替,稱作無限制的通配符類型炉媒,如泛型Set<E>的無限制通配符類型為Set<?>踪区,讀作某個(gè)類型的集合。通配符類型是安全的吊骤,原生態(tài)類型不安全缎岗。

不在新代碼中使用原生態(tài)類型這條規(guī)則有兩種例外情況:
1.在類文字中必須使用原生態(tài)類型

//正確的用法
List.class
String[].class
int.class

//錯(cuò)誤的用法
List<String.class>
List<?>.class

2.在instanceof操作符中必須使用原生態(tài)類型

if (o instanceof Set) {
    Set<?> m = (Set<?>)o;
}

上述兩種例外都是源于泛型信息可以在運(yùn)行時(shí)被擦除

使用原生態(tài)類型會在運(yùn)行時(shí)導(dǎo)致異常水援,因此不要在新代碼中使用密强。
原生態(tài)類型只是為了與引入泛型之前的遺留代碼進(jìn)行兼容和互用而提供的。
Set<Object>是個(gè)參數(shù)化類型蜗元,表示可以保護(hù)任意對象類型的一個(gè)集合或渤;
Set<?>則是一個(gè)通配符類型,表示只能包含某種未知對象類型的一個(gè)集合奕扣;
Set則是個(gè)原生態(tài)類型薪鹦。

2.消除非受檢警告

用泛型編程時(shí),會遇到很多編譯器警告:
非受檢強(qiáng)制轉(zhuǎn)換警告
非受檢方法調(diào)用警告
非受檢普通數(shù)組創(chuàng)建警告
非受檢轉(zhuǎn)換警告
要盡可能地消除每一個(gè)非受檢警告惯豆,這可以確保代碼是類型安全的池磁,意味著代碼在運(yùn)行時(shí)不會出現(xiàn)ClassCastException異常。

現(xiàn)代IDE工具都會提示這種警告信息楷兽,使用泛型時(shí)地熄,如有這種非受檢警告,按照IDE工具的提示逐個(gè)消除就可以了芯杀。

//含警告信息的泛型使用
Set<Lark> exaltation = new HashSet();

//消除警告信息的端考、類型安全的泛型使用
Set<Lark> exaltation = new HashSet<Lark>();

SuppressWarnings注解可以用在任何粒度的級別中雅潭,從單獨(dú)的局部變量聲明到整個(gè)類的定義都可以。應(yīng)該始終在盡可能小的范圍中使用SuppressWarnings注解却特,永遠(yuǎn)不要在整個(gè)類上使用SuppressWarnings扶供,因?yàn)檫@么做可能會掩蓋重要的警告信息。
每當(dāng)使用SuppressWarnings("unchecked")注解時(shí)裂明,都要添加一條注釋椿浓,說明為什么這么做是安全的。這樣做可以幫助他人理解代碼闽晦,更重要的是扳碍,可以盡量減少其他人修改代碼后導(dǎo)致計(jì)算不安全的概率。

非受檢警告很重要尼荆,不要忽略它們左腔。每一條警告都表示可能在運(yùn)行時(shí)拋出ClassCastException異常,要盡最大的努力消除這些警告捅儒。如果無法消除非受檢警告液样,同時(shí)又足以證明引起警告的代碼是類型安全的,就可以在盡可能小的范圍中巧还,用@SuppressWarnings("unchecked")注解禁止該警告鞭莽,并把禁止該警告的原因注釋記錄下來。

3.列表優(yōu)先于數(shù)組

數(shù)組與泛型相比麸祷,有兩個(gè)重要的不同點(diǎn):
1.數(shù)組是協(xié)變的
協(xié)變指的是如果Sub為Super的子類型澎怒,那么數(shù)組類型Sub[]就是Super[]的子類型;
泛型是不可變的阶牍,對于任意兩個(gè)不同的類型Type1和Type2喷面,List<Type1>既不是List<Type2>的子類型,也不是List<Type2>的超類型走孽。
2.數(shù)組是具體化的
數(shù)組在運(yùn)行時(shí)才知道并檢查它們的元素類型約束惧辈;
泛型則通過類型擦除來實(shí)現(xiàn),它在編譯時(shí)強(qiáng)化它們的類型信息磕瓷,在運(yùn)行時(shí)丟棄(或擦除)它們的元素類型信息盒齿。

由于數(shù)組的協(xié)變性和具體化,它是有缺陷的:

//數(shù)組具有協(xié)變性困食,Object是Long的父類边翁,聲明合法
Object[] objectArray = new Long[1];
//Long[] 退化為Object[],此處賦值也是合法的
objectArray[0] = "I don't fit in"; 

上述代碼可以通過編譯硕盹,但運(yùn)行時(shí)卻拋出ArrayStoreException符匾。
改為列表后,則無法通過編譯時(shí)的類型檢查:

//無法通過編譯瘩例,List<Object>和List<Long>是不同的類型
List<Object> ol = new ArrayList<Long>();
ol.add("I don't fit in");

因?yàn)閿?shù)組和泛型之間有著根本性的區(qū)別待讳,數(shù)組和泛型不能很好地混合使用芒澜。如下列類型的表達(dá)式都是非法的:new List<E>[]、new List<String>[]创淡、new E[]。
創(chuàng)建泛型數(shù)組是非法的南吮,是因?yàn)榉盒蛿?shù)組不是類型安全的琳彩。如下代碼所示:

List<String>[] strLists = new List<String>[1]; //假設(shè)此處合法
List<Integer> intList = Arrays.asList(42);
Object[] objects = strLists; //數(shù)組是協(xié)變的,此處合法
objects[0] = intList;
String s = strLists[0].get(0); //運(yùn)行時(shí)ClassCastException異常

當(dāng)?shù)玫椒盒蛿?shù)組創(chuàng)建錯(cuò)誤時(shí)部凑,最好的解決辦法通常是優(yōu)先使用集合類型List<E>露乏,而不是數(shù)組類型E[]。這樣可能會損失一些性能或簡潔性涂邀,但換回的卻是更高的類型安全性和互用性瘟仿。

數(shù)組和泛型有著非常不同的類型規(guī)則。數(shù)組是協(xié)變且可以具體化的比勉;泛型是不可變的且可以被擦除的劳较。因此,數(shù)組提供了運(yùn)行時(shí)的類型安全浩聋,但沒有編譯時(shí)的類型安全观蜗,對于泛型也一樣。
一般來說衣洁,數(shù)組和泛型不能很好地混合使用墓捻,如果將它們混合使用,且得到了編譯器的錯(cuò)誤或警告坊夫,第一反應(yīng)就應(yīng)該是用列表代替數(shù)組砖第。

4.優(yōu)先考慮泛型

編寫自己的泛型相對比較困難,但很值得花時(shí)間去學(xué)習(xí)如何編寫环凿。
下面以一個(gè)Stack類為例來說明:

public class Stack {
    private Object[] elements;
    private int size = 0;
    private static final int DEFAULT_INITIAL_CAPACITY = 16;
    
    public Stack() {
        elements = new Object[DEFAULT_INITIAL_CAPACITY];
    }
    
    public void push(Object e) {
        ensureCapacity();
        elements[size++] = e;
    }
    
    public Object pop() {
        if (size == 0) {
            throw new EmptyStackException();
        }
        Object result = elements[--size];
        elements[size] = null;
        return result;
    }
    
    public boolean isEmpty() {
        return size == 0;
    }
    
    private void ensureCapacity() {
        if (elements.length == size) {
            elements = Arrays.copyOf(elements, 2 * DEFAULT_INITIAL_CAPACITY + 1);
        }
    }
}

上述Stack類的實(shí)現(xiàn)梧兼,主要問題有如下兩點(diǎn):
1.push操作無法保證類型安全

//可以向stack中放入任意類型
Stack stack = new Stack();
stack.push("stack");
stack.put(new Integer(100));

2.pop操作獲得元素需要外部手工進(jìn)行類型轉(zhuǎn)換,且可能會產(chǎn)生ClassCastException異常拷邢。

String str = (String)stack.pop();

將上述Stack類進(jìn)行泛型化袱院,主要步驟為:
1.給它的聲明添加一個(gè)或者多個(gè)類型參數(shù)
2.用相應(yīng)的類型參數(shù)替換所有的Object類型,嘗試編譯

public class Stack<E> {
    private E[] elements;
    private int size = 0;
    private static final int DEFAULT_INITIAL_CAPACITY = 16;
    
    public Stack() {
        //此處提示錯(cuò)誤瞭稼,無法通過編譯忽洛,因?yàn)闊o法創(chuàng)建泛型數(shù)組
        elements = new E[DEFAULT_INITIAL_CAPACITY];
    }
    
    public void push(E e) {
        ensureCapacity();
        elements[size++] = e;
    }
    
    public E pop() {
        if (size == 0) {
            throw new EmptyStackException();
        }
        E result = elements[--size];
        elements[size] = null;
        return result;
    }
    
    public boolean isEmpty() {
        return size == 0;
    }
    
    private void ensureCapacity() {
        if (elements.length == size) {
            elements = Arrays.copyOf(elements, 2 * DEFAULT_INITIAL_CAPACITY + 1);
        }
    }
}

消除泛型數(shù)組的方法有兩種:
1.直接繞過創(chuàng)建泛型數(shù)組,創(chuàng)建一個(gè)Object數(shù)組

//用法合法环肘,但整體上而言不是類型安全的
elements = (E[])Object[DEFAULT_INITIAL_CAPACITY];

2.將域的類型從E[]改為Object[](推薦使用此種方法)

public class Stack<E> {
    private Object[] elements;
    ...

    public Stack() {
        elements = new Object[DEFAULT_INITIAL_CAPACITY];
    }

    public E pop() {
        if (size == 0) {
            throw new EmptyStackException();
        }
        E result = (E) elements[--size];
        elements[size] = null;
        return result;
    }
}

使用泛型比使用需要在客戶端代碼中進(jìn)行轉(zhuǎn)換的類型來得更加安全欲虚,也更加容易。在設(shè)計(jì)新類型時(shí)悔雹,要確保它們不需要這種轉(zhuǎn)換就可以使用复哆,這通常意味著要把類做成是泛型的欣喧。

5.優(yōu)先考慮泛型方法

靜態(tài)工具方法通常比較適合泛型化。
編寫泛型方法與編寫泛型類相似梯找,如下述代碼:

public static Set union(Set s1, Set s2) {
    Set result = new HashSet(s1);
    result.addAll(s2);
    return result;
}

上述union方法并不是類型安全的唆阿,將其泛型化的代碼如下:

public static <E> Set<E> union(Set<E> s1, Set<E> s2) {
    Set<E> result = new HashSet<E>(s1);
    result.addAll(s2);
    return result;
} 

泛型后的union方法不僅適用性更強(qiáng),也是類型安全的锈锤,它確保了待合并集合的類型一致性驯鳖,外部使用也無需進(jìn)行手工強(qiáng)制轉(zhuǎn)換。

泛型方法就像泛型一樣久免,使用起來比要求客戶端轉(zhuǎn)換輸入?yún)?shù)并返回值的方法來的更加安全浅辙,也更加容易。

6.利用有限制通配符來提升API的靈活性

參數(shù)類型是不可變的阎姥,對于任意兩個(gè)截然不同的類型Type1和Type2而言记舆,List<Type1>既不是List<Type2>的子類型,也不是它的超類型呼巴。如List<String>并不是List<Object>的子類型泽腮,這似乎與直覺相悖,但實(shí)際上是有意義的伊磺,你可以將任何對象放進(jìn)一個(gè)List<Object>中盛正,卻只能將字符串放進(jìn)List<String>中。

個(gè)人理解:泛型的參數(shù)類型是給編譯器使用的屑埋,供編譯器在獲取實(shí)參時(shí)進(jìn)行類型檢查豪筝,在返回結(jié)果時(shí)進(jìn)行類型轉(zhuǎn)換,在編譯完成后的字節(jié)碼中摘能,泛型參數(shù)類型信息是被擦除了的续崖。即是說,Java的泛型機(jī)制是在編譯階段實(shí)現(xiàn)的团搞,編譯生成的字節(jié)碼在運(yùn)行期間并不包含泛型的類型信息严望。正是由于這種類型擦除機(jī)制,導(dǎo)致泛型并不具備協(xié)變性逻恐,才能保證泛型的類型安全像吻。

泛型不具備協(xié)變性,但有時(shí)复隆,我們又需要使用協(xié)變帶來的靈活性拨匆,于是Java提供了有限制的通配符類型這種特殊的參數(shù)化類型:
GenericType<? extends E>:子類型通配符,通配符?表示E的某個(gè)子類型
GenericType<? super E>:超類型通配符挽拂,通配符?表示E的某個(gè)超類型
考慮Stack的公共API:

public class Stack<E> {
    public Stack();
    public void push(E e);
    public E pop();
    public boolean isEmpty();
}

假如我們想增加一個(gè)方法惭每,讓它按順序把一系列元素添加到Stack中,嘗試如下:

public void pushAll(Iterable<E> src) {
    for (E e : src) {
        push(e);
    }
}

如果src中的元素類型與Stack的泛型參數(shù)類型完全匹配亏栈,是完全沒有問題的台腥。但考慮這樣一種情形:有一個(gè)Stack<Number>宏赘,且調(diào)用了push(int val),從邏輯上講黎侈,下面的實(shí)現(xiàn)應(yīng)該是可以的:

Stack<Number> stack = new Stack<Number>();
Iterable<Integer> integers = ...;
stack.pushAll(integers);

實(shí)際情況是上述辦法并不可行察署,會導(dǎo)致編譯錯(cuò)誤。
顯然峻汉,我們的目的是想將E的某個(gè)子類型也放入Stack中箕母,可以利用子類型通配符來做有限制的規(guī)定:

public void pushAll(Iterable<? extends E> src) {
    for (E e : src) {
        push(e);
    }
}

假設(shè)現(xiàn)在需要編寫一個(gè)popAll方法,使之與pushAll方法相呼應(yīng)俱济,popAll方法從Stack中彈出每個(gè)元素,并將這些元素添加到指定的集合中钙勃,嘗試如下:

public void popAll(Collection<E> dst) {
    while (!isEmpty()) {
        dst.add(pop());
    }
}

如果dst的元素類型與Stack完全匹配蛛碌,上述實(shí)現(xiàn)是沒有問題的。但考慮這樣一種情形:有一個(gè)Stack<Number>和Collection<Object>辖源,從邏輯上講蔚携,下面的實(shí)現(xiàn)應(yīng)該是可以的:

Stack<Number> numStack = new Stack<Number>();
Collection<Object> coll = ...;
numStack.popAll(coll);

實(shí)際情況是上述辦法并不可行,會導(dǎo)致編譯錯(cuò)誤克饶。Collection<Object>并不是Collection<Number>的超類型酝蜒。
我們的目的是為了將類型為E的元素加入到目標(biāo)泛型集合中,且目標(biāo)集合的泛型參數(shù)類型只要是類型E的父類型即可矾湃,Java提供了父類型通配符來實(shí)現(xiàn)這種需求:

//此處的限定是:通配符類型是泛型參數(shù)類型的父類即可
public void popAll(Collection<? super E> dst) {
    while(!isEmpty()) {
        dst.add(pop());
    }
}

為了獲得最大限度的靈活性亡脑,要在表示生產(chǎn)者或者消費(fèi)者的輸入?yún)?shù)上使用通配符類型。
為了便于記住要使用哪種通配符邀跃,引入下面的助記符:
PECS表示producer-extends霉咨,consumer-super。
如果參數(shù)化類型表示一個(gè)T生產(chǎn)者拍屑,就使用<? extends T>途戒;如果它表示一個(gè)T消費(fèi)者,就使用<? super T>僵驰。在Stack示例中喷斋,pushAll的src參數(shù)產(chǎn)生E實(shí)例供Stack使用,因此src相應(yīng)的類型為Iterable<? extends E>蒜茴;popAll的dst參數(shù)通過Stack消費(fèi)E實(shí)例星爪,因此dst相應(yīng)的類型為Collection<? super E>。
PECS助記符突出了使用通配符類型的基本原則矮男。

在API中使用通配符類型雖然比較需要技巧移必,但它可以使API變得靈活得多。
如果編寫的是將被廣泛使用的類庫毡鉴,則一定要適當(dāng)?shù)乩猛ㄅ浞愋汀?br> 需要記住的基本原則是:producer-extends,comsumer-super(PECS)崔泵。
所有的comparable和comparator都是消費(fèi)者秒赤。

7.優(yōu)先考慮類型安全的異構(gòu)容器

泛型最常用于集合,如Set和Map憎瘸,以及單元素的容器入篮,如ThreadLocal和AtomicReference。在這些用法中幌甘,它都充當(dāng)了被參數(shù)化了的容器潮售。這樣就限制了每個(gè)容器只能有固定數(shù)目的類型參數(shù)。一般來說锅风,這種情況正是所想要的酥诽,一個(gè)Set只有一個(gè)類型參數(shù),表示它的元素類型皱埠;一個(gè)Map有兩個(gè)類型參數(shù)肮帐,表示它的鍵和值類型。
但是边器,有時(shí)候你會需要更多的靈活性训枢。例如,數(shù)據(jù)庫行可以有任意多列忘巧,如何才能以類型安全的方式訪問所有列哪恒界?Java泛型提供了一種方法來解決這個(gè)問題:將鍵(key)進(jìn)行參數(shù)化而不是將容器參數(shù)化,然后將參數(shù)化的鍵提交給容器砚嘴,來插入或者獲取值十酣,用泛型系統(tǒng)來確保值的類型與它的鍵相符

類Class在Java1.5中被泛化了枣宫,類的類型從字面上看不再只是簡單的Class婆誓,而是Class<T>,意味著String.class是屬于Class<String>類型也颤,Integer.class屬于Class<Integer>類型洋幻。
當(dāng)一個(gè)類的字面文字被用在方法中,來傳達(dá)編譯時(shí)和運(yùn)行時(shí)的類型信息時(shí)翅娶,被稱作type token文留。

假如需要設(shè)計(jì)一個(gè)Favorites類,它允許其客戶端從任意數(shù)量的其他類中竭沫,保存并獲得一個(gè)“最喜愛”的實(shí)例燥翅,代碼如下:

public class Favorites {
    private Map<Class<?>, Object> favorities = new HashMap<Class<?>, Object>();

    public <T> void putFavorite(Class<T> type, T instance) {
        if (type == null) {
            throw new NullPointerException("Type is null");
        }
        favorities.put(type, instance);
    }

    public <T> T getFavorite(Class<T> type) {
        return type.cast(favorities.get(type));
    }

    public static void main(String[] args) {
        Favorites f = new Favorites();
        f.putFavorite(String.class, "Java");
        f.putFavorite(Integer.class, 0xcafebabe);
        f.putFavorite(Class.class, Favorites.class);

        String fString = f.getFavorite(String.class);
        int fInteger = f.getFavorite(Integer.class);
        Class<?> fClass = f.getFavorite(Class.class);

        System.out.printf("%s %x %s%n", fString, fInteger, fClass.getSimpleName());
    }
}
//代碼打印結(jié)果為:Java cafebabe Favorites

Favorites實(shí)例是類型安全的:當(dāng)你向它請求String的時(shí)候,它不會返回一個(gè)Integer蜕提。同時(shí)它也是異構(gòu)的:不像普通的map森书,它的所有鍵都是不同類型的
像Favorites這種類被稱為類型安全的異構(gòu)容器
Favorites使用的類型令牌是無限制的凛膏,還可以利用有限制類型參數(shù)或有限制通配符來限制可以表示的類型:

    public <T extends Annotation> T getAnnotation(Class<T> annotationType);

    Annotation getAnnotation(AnnotatedElement element, String annotationTypeName) {
        Class<?> annotationType = null;
        try {
            annotationType = Class.forName(annotationTypeName);
        } catch (Exception e) {
            throw new IllegalArgumentException();
        }
        return element.getAnnotation(annotationType.asSubclass(Annotation.class));
    }

集合API說明了泛型的常見用法杨名,它限制每個(gè)容器只能有固定數(shù)目的類型參數(shù)猜旬。
可以將類型參數(shù)放在鍵上而不是容器上來避開這一限制福铅。
對于這種類型安全的異構(gòu)容器,可以用Class對象作為鍵匹涮。
以這種方式使用的Class對象被稱作類型令牌吁断。
也可以使用定制的鍵類型趁蕊,例如,用一個(gè)DatabaseRow類型表示一個(gè)數(shù)據(jù)庫行(容器)仔役,用泛型Column<T>作為它的鍵掷伙。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市又兵,隨后出現(xiàn)的幾起案子炎咖,更是在濱河造成了極大的恐慌,老刑警劉巖寒波,帶你破解...
    沈念sama閱讀 212,542評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異升熊,居然都是意外死亡俄烁,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,596評論 3 385
  • 文/潘曉璐 我一進(jìn)店門级野,熙熙樓的掌柜王于貴愁眉苦臉地迎上來页屠,“玉大人,你說我怎么就攤上這事蓖柔〕狡螅” “怎么了?”我有些...
    開封第一講書人閱讀 158,021評論 0 348
  • 文/不壞的土叔 我叫張陵况鸣,是天一觀的道長牢贸。 經(jīng)常有香客問我,道長镐捧,這世上最難降的妖魔是什么潜索? 我笑而不...
    開封第一講書人閱讀 56,682評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮懂酱,結(jié)果婚禮上竹习,老公的妹妹穿的比我還像新娘。我一直安慰自己列牺,他們只是感情好整陌,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,792評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般泌辫。 火紅的嫁衣襯著肌膚如雪随夸。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,985評論 1 291
  • 那天甥郑,我揣著相機(jī)與錄音逃魄,去河邊找鬼。 笑死澜搅,一個(gè)胖子當(dāng)著我的面吹牛伍俘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播勉躺,決...
    沈念sama閱讀 39,107評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼癌瘾,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了饵溅?” 一聲冷哼從身側(cè)響起妨退,我...
    開封第一講書人閱讀 37,845評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蜕企,沒想到半個(gè)月后咬荷,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,299評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡轻掩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,612評論 2 327
  • 正文 我和宋清朗相戀三年幸乒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片唇牧。...
    茶點(diǎn)故事閱讀 38,747評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡罕扎,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出丐重,到底是詐尸還是另有隱情腔召,我是刑警寧澤,帶...
    沈念sama閱讀 34,441評論 4 333
  • 正文 年R本政府宣布扮惦,位于F島的核電站臀蛛,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏崖蜜。R本人自食惡果不足惜掺栅,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,072評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望纳猪。 院中可真熱鬧氧卧,春花似錦、人聲如沸氏堤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,828評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至闪檬,卻和暖如春星著,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背粗悯。 一陣腳步聲響...
    開封第一講書人閱讀 32,069評論 1 267
  • 我被黑心中介騙來泰國打工虚循, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人样傍。 一個(gè)月前我還...
    沈念sama閱讀 46,545評論 2 362
  • 正文 我出身青樓横缔,卻偏偏與公主長得像,于是被迫代替她去往敵國和親衫哥。 傳聞我的和親對象是個(gè)殘疾皇子茎刚,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,658評論 2 350

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