Java 泛型與通配符

參考地址:
《Java 泛型镜硕,你了解類型擦除嗎闻妓?》
《Java中的逆變與協(xié)變》
《java 泛型中 T、E ... 和 問號(通配符)的區(qū)別》

:本文是在 frank909 的文章 《Java 泛型渗常,你了解類型擦除嗎壮不?》 的基礎(chǔ)上,參考其他文章并重新總結(jié)排版而來的皱碘。


一. 泛型

泛型的英文是 generics询一,generic 的意思是通用,而翻譯成中文癌椿,“泛”應(yīng)該意為廣泛健蕊,型是類型。所以泛型就是能廣泛適用的類型如失。

1.1 泛型的定義

泛型還有一種較為準(zhǔn)確的說法就是為了參數(shù)化類型绊诲,或者說可以將類型當(dāng)作參數(shù)傳遞給一個類或者是方法。

那么褪贵,如何解釋類型參數(shù)化呢?

public class Cache {
    Object value;

    public Object getValue() {
        return value;
    }

    public void setValue(Object value) {
        this.value = value;
    }
}

假設(shè) Cache 能夠存取任何類型的值抗俄,于是脆丁,我們可以這樣使用它。

Cache cache = new Cache();
cache.setValue(134);
int value = (int) cache.getValue();
cache.setValue("hello");
String value1 = (String) cache.getValue();

使用的方法也很簡單动雹,只要我們做正確的強(qiáng)制轉(zhuǎn)換就好了槽卫。

但是,泛型卻給我們帶來了不一樣的編程體驗(yàn)胰蝠。

public class Cache<T> {
    T value;

    public Object getValue() {
        return value;
    }

    public void setValue(T value) {
        this.value = value;
    }

}

這就是泛型歼培,它將 value 這個屬性的類型也參數(shù)化了,這就是所謂的參數(shù)化類型茸塞。再看它的使用方法躲庄。

Cache<String> cache1 = new Cache<String>();
cache1.setValue("123");
String value2 = cache1.getValue();

Cache<Integer> cache2 = new Cache<Integer>();
cache2.setValue(456);
int value3 = cache2.getValue();

最顯而易見的好處就是它不再需要對取出來的結(jié)果進(jìn)行強(qiáng)制轉(zhuǎn)換了。但钾虐,還有另外一點(diǎn)不同噪窘。

泛型不再需要對取出來的結(jié)果進(jìn)行強(qiáng)制轉(zhuǎn)換

泛型除了可以將類型參數(shù)化外,而參數(shù)一旦確定好效扫,如果類似不匹配倔监,編譯器就不通過直砂。
上面代碼顯示,無法將一個 String 對象設(shè)置到 cache2 中浩习,因?yàn)榉盒妥屗唤邮?Integer 的類型静暂。

所以,綜合上面信息谱秽,我們可以得到下面的結(jié)論籍嘹。

  1. 與普通的 Object 代替一切類型這樣簡單粗暴而言,泛型使得數(shù)據(jù)的類別可以像參數(shù)一樣由外部傳遞進(jìn)來弯院。它提供了一種擴(kuò)展能力辱士。它更符合面向抽象開發(fā)的軟件編程宗旨。
  2. 當(dāng)具體的類型確定后听绳,泛型又提供了一種類型檢測的機(jī)制颂碘,只有相匹配的數(shù)據(jù)才能正常的賦值,否則編譯器就不通過椅挣。所以說头岔,它是一種類型安全檢測機(jī)制,一定程度上提高了軟件的安全性防止出現(xiàn)低級的失誤鼠证。
  3. 泛型提高了程序代碼的可讀性峡竣,不必要等到運(yùn)行的時候才去強(qiáng)制轉(zhuǎn)換,在定義或者實(shí)例化階段量九,因?yàn)?Cache< String > 這個類型顯化的效果适掰,程序員能夠一目了然猜測出代碼要操作的數(shù)據(jù)類型。
    下面的文章荠列,我們正常介紹泛型的相關(guān)知識类浪。

1.2 泛型的使用

泛型按照使用情況可以分為 3 種:

  1. 泛型類。
  2. 泛型方法肌似。
  3. 泛型接口费就。

1.2.1 泛型類

我們可以這樣定義一個泛型類。

public class Test<T> {
    T field1;
}

尖括號 < > 中的 T 被稱作是類型參數(shù)川队,用于指代任何類型力细。事實(shí)上,T 只是一種習(xí)慣性寫法固额,如果你愿意眠蚂。你可以這樣寫。

public class Test<Hello> {
    Hello field1;
}

但出于規(guī)范的目的对雪,Java 還是建議我們用單個大寫字母來代表類型參數(shù)河狐。常見的如:

  1. T 代表一般的任何類。
  2. E 代表 Element 的意思,或者 Exception 異常的意思馋艺。
  3. K 代表 Key 的意思栅干。
  4. V 代表 Value 的意思,通常與 K 一起配合使用捐祠。
  5. S 代表 Subtype 的意思碱鳞,文章后面部分會講解示意。

如果一個類被 <T> 的形式定義踱蛀,那么它就被稱為是泛型類窿给。

那么對于泛型類怎么樣使用呢?

Test<String> test1 = new Test<>();
Test<Integer> test2 = new Test<>();

只要在對泛型類創(chuàng)建實(shí)例的時候率拒,在尖括號中賦值相應(yīng)的類型便是崩泡。T 就會被替換成對應(yīng)的類型,如 String 或者是 Integer猬膨。你可以相像一下角撞,當(dāng)一個泛型類被創(chuàng)建時,內(nèi)部自動擴(kuò)展成下面的代碼勃痴。

public class Test<String> {
    String field1;
}

當(dāng)然谒所,泛型類不至接受一個類型參數(shù),它還可以這樣接受多個類型參數(shù)沛申。

public class MultiType <E,T>{
    E value1;
    T value2;

    public E getValue1(){
        return value1;
    }

    public T getValue2(){
        return value2;
    }
}

1.2.2 泛型方法

public class Test1 {

    public <T> void testMethod(T t){

    }
}

泛型方法與泛型類稍有不同的地方是劣领,類型參數(shù)也就是尖括號那一部分是寫在返回值前面的。<T> 中的 T 被稱為類型參數(shù)铁材,而方法中的 T 被稱為參數(shù)化類型哪审,它不是運(yùn)行時真正的參數(shù)掘剪。

當(dāng)然馒稍,聲明的類型參數(shù)蹈矮,其實(shí)也是可以當(dāng)作返回值的類型的洒宝。

public  <T> T testMethod1(T t){
    return null;
}

1.2.3 泛型類與泛型方法共存

public class Test1<T>{

    public void testMethod(T t){
        System.out.println(t.getClass().getName());
    }
    public  <T> T testMethod1(T t){
        return t;
    }
}

上面代碼中厨疙,Test1< T > 是泛型類薇正,testMethod 是泛型類中的普通方法洛心,而 testMethod1 是一個泛型方法缴守。而泛型類中的類型參數(shù)與泛型方法中的類型參數(shù)是沒有相應(yīng)的聯(lián)系的葬毫,泛型方法始終以自己定義的類型參數(shù)為準(zhǔn)

所以屡穗,針對上面的代碼贴捡,我們可以這樣編寫測試代碼。

Test1<String> t = new Test1();
t.testMethod("generic");
Integer i = t.testMethod1(new Integer(1));

泛型類的實(shí)際類型參數(shù)是 String村砂,而傳遞給泛型方法的類型參數(shù)是 Integer烂斋,兩者不想干。

但是,為了避免混淆汛骂,如果在一個泛型類中存在泛型方法罕模,那么兩者的類型參數(shù)最好不要同名。比如帘瞭,Test1< T > 代碼可以更改為這樣:

public class Test1<T>{

    public  void testMethod(T t){
        System.out.println(t.getClass().getName());
    }
    public  <E> E testMethod1(E e){
        return e;
    }
}

1.2.4 泛型接口

泛型接口和泛型類差不多淑掌,所以一筆帶過。

public interface Iterable<T> {
}

1.3 泛型的類型擦除

泛型是 Java 1.5 版本才引進(jìn)的概念蝶念,在這之前是沒有泛型的概念的抛腕,但顯然,泛型代碼能夠很好地和之前版本的代碼很好地兼容媒殉。

這是因?yàn)椋?strong>泛型信息只存在于代碼編譯階段担敌,在進(jìn)入 JVM 之前,與泛型相關(guān)的信息會被擦除掉廷蓉,專業(yè)術(shù)語叫做類型擦除全封。

通俗地講,泛型類和普通類在 java 虛擬機(jī)內(nèi)是沒有什么特別的地方苦酱∈勖玻回顧文章開始時的那段代碼

List<String> l1 = new ArrayList<String>();
List<Integer> l2 = new ArrayList<Integer>();

System.out.println(l1.getClass() == l2.getClass());

打印的結(jié)果為 true 是因?yàn)?List< String > 和 List< Integer > 在 jvm 中的 Class 都是 List.class。

泛型信息被擦除了疫萤。

可能同學(xué)會問颂跨,那么類型 String 和 Integer 怎么辦?

答案是泛型轉(zhuǎn)譯扯饶。

public class Erasure <T>{
    T object;

    public Erasure(T object) {
        this.object = object;
    }

}

Erasure 是一個泛型類恒削,我們查看它在運(yùn)行時的狀態(tài)信息可以通過反射。

Erasure<String> erasure = new Erasure<String>("hello");
Class eclz = erasure.getClass();
System.out.println("erasure class is:"+eclz.getName());

打印的結(jié)果是

erasure class is:com.frank.test.Erasure

Class 的類型仍然是 Erasure 并不是 Erasure<T> 這種形式尾序,那我們再看看泛型類中 T 的類型在 jvm 中是什么具體類型钓丰。

Field[] fs = eclz.getDeclaredFields();
for ( Field f:fs) {
    System.out.println("Field name "+f.getName()+" type:"+f.getType().getName());
}

打印結(jié)果是

Field name object type:java.lang.Object

那我們可不可以說,泛型類被類型擦除后每币,相應(yīng)的類型就被替換成 Object 類型呢携丁?

這種說法,不完全正確兰怠。

我們更改一下代碼梦鉴。

public class Erasure <T extends String>{
//  public class Erasure <T>{
    T object;

    public Erasure(T object) {
        this.object = object;
    }

}

現(xiàn)在再看測試結(jié)果:

Field name object type:java.lang.String

我們現(xiàn)在可以下結(jié)論了,在泛型類被類型擦除的時候揭保,之前泛型類中的類型參數(shù)部分如果沒有指定上限肥橙,如 < T > 則會被轉(zhuǎn)譯成普通的 Object 類型,如果指定了上限如 < T extends String> 則類型參數(shù)就被替換成類型上限秸侣。

所以存筏,在反射中宠互。

public class Erasure <T>{
    T object;

    public Erasure(T object) {
        this.object = object;
    }

    public void add(T object){

    }

}

add() 這個方法對應(yīng)的 Method 的簽名應(yīng)該是 Object.class。

Erasure<String> erasure = new Erasure<String>("hello");
Class eclz = erasure.getClass();
System.out.println("erasure class is:"+eclz.getName());

Method[] methods = eclz.getDeclaredMethods();
for ( Method m:methods ){
    System.out.println(" method:"+m.toString());
}

打印結(jié)果是

method:public void com.frank.test.Erasure.add(java.lang.Object)

也就是說椭坚,如果你要在反射中找到 add 對應(yīng)的 Method予跌,你應(yīng)該調(diào)用 getDeclaredMethod("add",Object.class) 否則程序會報錯,提示沒有這么一個方法藕溅,原因就是類型擦除的時候匕得,T 被替換成 Object 類型了。

1.4 泛型類型擦除的局限性

類型擦除巾表,是泛型能夠與之前的 java 版本代碼兼容共存的原因汁掠。但也因?yàn)轭愋筒脸鼤ǖ艉芏嗬^承相關(guān)的特性集币,這是它帶來的局限性考阱。

理解類型擦除有利于我們繞過開發(fā)當(dāng)中可能遇到的雷區(qū),同樣理解類型擦除也能讓我們繞過泛型本身的一些限制鞠苟。比如:

類型擦除帶來的局限性

正常情況下乞榨,因?yàn)榉盒偷南拗疲幾g器不讓最后一行代碼編譯通過当娱,因?yàn)轭愃撇黄ヅ涑约龋牵趯︻愋筒脸牧私饪缦福梅瓷漯幸校覀兛梢岳@過這個限制。

public interface List<E> extends Collection<E>{

     boolean add(E e);
}

上面是 List 和其中的 add() 方法的源碼定義冀惭。

因?yàn)?E 代表任意的類型震叙,所以類型擦除時,add 方法其實(shí)等同于

boolean add(Object obj);

那么散休,利用反射媒楼,我們繞過編譯器去調(diào)用 add 方法。

public class ToolTest {


    public static void main(String[] args) {
        List<Integer> ls = new ArrayList<>();
        ls.add(23);
//      ls.add("text");
        try {
            Method method = ls.getClass().getDeclaredMethod("add",Object.class);


            method.invoke(ls,"test");
            method.invoke(ls,42.9f);
        } catch (NoSuchMethodException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        for ( Object o: ls){
            System.out.println(o);
        }

    }

}

打印結(jié)果是:

23
test
42.9

可以看到戚丸,利用類型擦除的原理划址,用反射的手段就繞過了正常開發(fā)中編譯器不允許的操作限制。

1.5 泛型需注意問題

1.5.1 泛型不接受 8 種基本數(shù)據(jù)類型

泛型類或者泛型方法中限府,不接受 8 種基本數(shù)據(jù)類型猴鲫。所以,你沒有辦法進(jìn)行這樣的編碼:

List<int> li = new ArrayList<>();
List<boolean> li = new ArrayList<>();

需要使用它們對應(yīng)的包裝類谣殊。

List<Integer> li = new ArrayList<>();
List<Boolean> li1 = new ArrayList<>();

對泛型方法的困惑

public <T> T test(T t){
    return null;
}

有的同學(xué)可能對于連續(xù)的兩個 T 感到困惑,其實(shí) < T > 是為了說明類型參數(shù)牺弄,是聲明,而后面的不帶尖括號的 T 是方法的返回值類型姻几。
你可以相像一下,如果 test() 這樣被調(diào)用

test("123");

那么實(shí)際上相當(dāng)于

public String test(String t);

1.5.2 Java 不能創(chuàng)建具體類型的泛型數(shù)組

這句話可能難以理解,代碼說明蛇捌。

List<Integer>[] li2 = new ArrayList<Integer>[];
List<Boolean> li3 = new ArrayList<Boolean>[];

這兩行代碼是無法在編譯器中編譯通過的抚恒。原因還是類型擦除帶來的影響。

List< Integer> 和 List< Boolean> 在 jvm 中等同于List< Object> 络拌,所有的類型信息都被擦除俭驮,程序也無法分辨一個數(shù)組中的元素類型具體是 List< Integer>類型還是 List< Boolean> 類型。

但是春贸,

List<?>[] li3 = new ArrayList<?>[10];
li3[1] = new ArrayList<String>();
List<?> v = li3[1];

借助于無限定通配符卻可以混萝,前面講過 ? 代表未知類型萍恕,所以它涉及的操作都基本上與類型無關(guān)逸嘀,因此 jvm 不需要針對它對類型作判斷,因此它能編譯通過允粤,但是崭倘,只提供了數(shù)組中的元素因?yàn)橥ㄅ浞颍荒茏x类垫,不能寫司光。比如,上面的 v 這個局部變量悉患,它只能進(jìn)行 get() 操作残家,不能進(jìn)行 add() 操作,這個在前面通配符的內(nèi)容小節(jié)中已經(jīng)講過购撼。

二. 通配符 "?"

除了用 < T > 表示泛型外跪削,還有 < ? > 這種形式。迂求? 被稱為通配符碾盐。

2.1 通配符 "?" 簡介

可能有同學(xué)會想,已經(jīng)有了 < T > 的形式了揩局,為什么還要引進(jìn) < ? > 這樣的概念呢毫玖?

class Base{}

class Sub extends Base{}

Sub sub = new Sub();
Base base = sub;            

上面代碼顯示,Base 是 Sub 的父類凌盯,它們之間是繼承關(guān)系付枫,所以 Sub 的實(shí)例可以給一個 Base 引用賦值,那么

List<Sub> lsub = new ArrayList<>();
List<Base> lbase = lsub;

最后一行代碼成立嗎驰怎?編譯會通過嗎阐滩?

答案是否定的。

編譯器不會讓它通過的县忌。Sub 是 Base 的子類掂榔,不代表 List<Sub> 和 List<Base> 有繼承關(guān)系继效。

但是,在現(xiàn)實(shí)編碼中装获,確實(shí)有這樣的需求瑞信,希望泛型能夠處理某一范圍內(nèi)的數(shù)據(jù)類型,比如某個類和它的子類穴豫,對此 Java 引入了通配符這個概念凡简。

所以,通配符的出現(xiàn)是為了指定泛型中的類型范圍精肃。

2.2 通配符的協(xié)變與逆變

通配符有 3 種形式秤涩。

  1. < ?> 被稱作無限定的通配符。
  2. < ? extends T> 被稱作有上限的通配符肋杖。
  3. < ? super T> 被稱作有下限的通配符溉仑。

2.2.1 無限定通配符

public void testWildCards(Collection<?> collection){
}

上面的代碼中,方法內(nèi)的參數(shù)是被無限定通配符修飾的 Collection 對象状植,它隱略地表達(dá)了一個意圖或者可以說是限定浊竟,那就是 testWidlCards() 這個方法內(nèi)部無需關(guān)注 Collection 中的真實(shí)類型,因?yàn)樗俏粗慕蚧K哉穸ǎ阒荒苷{(diào)用 Collection 中與類型無關(guān)的方法。

調(diào)用 Collection 中與類型無關(guān)的方法

我們可以看到肉拓,當(dāng) < ? > 存在時后频,Collection 對象喪失了 add() 方法的功能,編譯器不通過暖途。
我們再看代碼卑惜。

List<?> wildlist = new ArrayList<String>();
wildlist.add(123);// 編譯不通過

有人說,< ? > 提供了只讀的功能驻售,也就是它刪減了增加具體類型元素的能力露久,只保留與具體類型無關(guān)的功能。它不管裝載在這個容器內(nèi)的元素是什么類型欺栗,它只關(guān)心元素的數(shù)量毫痕、容器是否為空?我想這種需求還是很常見的吧迟几。

有同學(xué)可能會想消请,< ? > 既然作用這么渺小,那么為什么還要引用它呢类腮? ?

個人認(rèn)為臊泰,提高了代碼的可讀性,程序員看到這段代碼時蚜枢,就能夠迅速對此建立極簡潔的印象因宇,能夠快速推斷源碼作者的意圖七婴。

2.2.2 協(xié)變 < ? extends T>

Java 中 String 類型是繼承自 Object 的,姑且記做 String ≦ Object察滑,表示 String 是 Object 的子類型,String 的對象可以賦給 Object 的對象修肠。而 Object 的數(shù)組類型 Object[]贺辰,理解成是由 Object 構(gòu)造出來的一種新的類型,可以認(rèn)為是一種構(gòu)造類型嵌施,記f(Object)饲化,那么可以這么來描述協(xié)變和逆變:

  • 當(dāng) A ≦ B 時,如果有 f(A) ≦ f(B)吗伤,那么 f 叫做協(xié)變吃靠;
  • 當(dāng) A ≦ B 時,如果有 f(B) ≦ f(A)足淆,那么 f 叫做逆變巢块;
  • 如果上面兩種關(guān)系都不成立,則叫做不可變巧号。

< ? extends> 實(shí)現(xiàn)了泛型的協(xié)變族奢,比如:

List<? extends Number> list = new ArrayList<>();

“? extends Number” 則表示通配符 "?" 的上界為 Number,換句話說丹鸿,就是“? extends Number”可以代表 Number 或其子類越走,但代表不了 Number 的父類(如Object),因?yàn)橥ㄅ浞纳辖缡?Number靠欢。
于是有 "? extends Number" ≦ Number廊敌,則 List< ? extends Number> ≦ List< Number >。那么就有:

List<? extends Number> list001 = new ArrayList<Integer>();
List<? extends Number> list002 = new ArrayList<Float>();

但是這里不能向 list001, list002 添加除 null 以外的任意對象门怪÷獬海可以這樣理解一下,List< Integer > 可以添加 Interger 及其子類薪缆,List< Float >可以添加 Float 及其子類秧廉,List< Integer >, List< Float > 都是 List< ? extends Number >的子類型,如果能將 Float 的子類添加到 List< ? extends Number >中拣帽,就說明 Float 的子類也是可以添加到 List< Integer >中的疼电,顯然是不可行。故 Java 為了保護(hù)其類型一致减拭,禁止向 List< ? extends Number >添加任意對象蔽豺,不過卻可以添加 null。

2.2.3 逆變 < ? super >

< ? super > 實(shí)現(xiàn)了泛型的逆變拧粪,比如:

List<? super Number> list = new ArrayList<>();

"? super Number" 則表示通配符 "?" 的下界為 Number修陡。為了保護(hù)類型的一致性沧侥,因?yàn)?"? super Number" 可以是 Object 或其他 Number 的父類,因無法確定其類型魄鸦,也就不能往List< ? super Number >添加 Number 的任意父類對象宴杀。但是可以向 List< ? super Number >添加 Number 及其子類。

List<? super Number> list001 = new ArrayList<Number>();
List<? super Number> list002 = new ArrayList<Object>();
list001.add(new Integer(3));
list002.add(new Integer(3));

三. 通配符與泛型的區(qū)別

筆者參考了 《Java 泛型拾因,你了解類型擦除嗎旺罢?》《java 泛型中 T、E ... 和 問號(通配符)的區(qū)別》 兩篇文章中對于通配符與泛型的區(qū)別绢记,兩篇文章中筆者認(rèn)為后者的描述比較淺顯易懂扁达,前者的行文并沒有怎么理解。所以筆者比較推薦后者敘述的通配符與泛型的區(qū)別蠢熄。

首先跪解,泛型中 T, E 等符號是泛型類、泛型方法定義時候用的签孔。泛型類的定義緊跟在類名后面叉讥;泛型方法的定義緊跟修飾符后面(public)。

  • 泛型類:public class TestClassDefine<T>{}
  • 泛型方法:public <T> T testGenericMethodDefine(T t){}

通配符 "?"骏啰,通常是在變量賦值變量聲明時用的节吮。

List<?> unknownList;
List<? extends Number> unknownNumberList;
List<? super Integer> unknownBaseLineIntgerList;
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市判耕,隨后出現(xiàn)的幾起案子透绩,更是在濱河造成了極大的恐慌,老刑警劉巖壁熄,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件帚豪,死亡現(xiàn)場離奇詭異,居然都是意外死亡草丧,警方通過查閱死者的電腦和手機(jī)狸臣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來昌执,“玉大人烛亦,你說我怎么就攤上這事《埃” “怎么了煤禽?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長岖赋。 經(jīng)常有香客問我檬果,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任选脊,我火速辦了婚禮杭抠,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘恳啥。我一直安慰自己偏灿,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布角寸。 她就那樣靜靜地躺著菩混,像睡著了一般。 火紅的嫁衣襯著肌膚如雪扁藕。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天疚脐,我揣著相機(jī)與錄音亿柑,去河邊找鬼。 笑死棍弄,一個胖子當(dāng)著我的面吹牛望薄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播呼畸,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼痕支,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蛮原?” 一聲冷哼從身側(cè)響起卧须,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎儒陨,沒想到半個月后花嘶,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蹦漠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年椭员,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片笛园。...
    茶點(diǎn)故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡隘击,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出研铆,到底是詐尸還是另有隱情埋同,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布蚜印,位于F島的核電站莺禁,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏窄赋。R本人自食惡果不足惜哟冬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一楼熄、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧浩峡,春花似錦可岂、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至纸淮,卻和暖如春平斩,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背咽块。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工绘面, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人侈沪。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓揭璃,卻偏偏與公主長得像,于是被迫代替她去往敵國和親亭罪。 傳聞我的和親對象是個殘疾皇子瘦馍,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評論 2 355

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

  • ??在Effective中講到泛型之處提到了一個概念,類型擦除器应役,這是什么呢情组?接下來我們跟隨這篇文章探索類型擦除的...
    凌云_00閱讀 2,140評論 0 8
  • 泛型,一個孤獨(dú)的守門者扛吞。 大家可能會有疑問呻惕,我為什么叫做泛型是一個守門者。這其實(shí)是我個人的看法而已滥比,我的意思是說泛...
    jackcooper閱讀 442評論 2 2
  • 參數(shù)類型的好處 在 Java 引入泛型之前亚脆,泛型程序設(shè)計是用繼承實(shí)現(xiàn)的。ArrayList 類只維護(hù)一個 Obje...
    杰哥長得帥閱讀 880評論 0 3
  • 我見到她時盲泛,她蜷曲在床上濒持,所有的軀體都僵硬地擰著,似乎在與誰暗中較著勁寺滚。我看了一眼檢查單上的基本信息:任盈...
    伊莎貝拉的微笑閱讀 303評論 0 3
  • 最近由于工作需要柑营,研究了下小程序,不得不說村视,整個開發(fā)流程官套,官方都做的很完善,基本的組件也都實(shí)現(xiàn),而語法上奶赔,作為前端...
    Stevenzwzhai閱讀 218評論 0 0