深入理解 Java 泛型

?? 本文已歸檔到:「javacore

?? 本文中的示例代碼已歸檔到:「javacore

1. 為什么需要泛型

JDK5 引入了泛型機(jī)制蝉揍。

為什么需要泛型呢庸娱?回答這個問題前着绊,先讓我們來看一個示例。

public class NoGenericsDemo {
    public static void main(String[] args) {
        List list = new ArrayList<>();
        list.add("abc");
        list.add(18);
        list.add(new double[] {1.0, 2.0});
        Object obj1 = list.get(0);
        Object obj2 = list.get(1);
        Object obj3 = list.get(2);
        System.out.println("obj1 = [" + obj1 + "]");
        System.out.println("obj2 = [" + obj2 + "]");
        System.out.println("obj3 = [" + obj3 + "]");

        int num1 = (int)list.get(0);
        int num2 = (int)list.get(1);
        int num3 = (int)list.get(2);
        System.out.println("num1 = [" + num1 + "]");
        System.out.println("num2 = [" + num2 + "]");
        System.out.println("num3 = [" + num3 + "]");
    }
}
// Output:
// obj1 = [abc]
// obj2 = [18]
// obj3 = [[D@47089e5f]
// Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
// at io.github.dunwu.javacore.generics.NoGenericsDemo.main(NoGenericsDemo.java:23)

示例說明:

在上面的示例中熟尉,List 容器沒有指定存儲數(shù)據(jù)類型归露,這種情況下,可以向 List 添加任意類型數(shù)據(jù)斤儿,編譯器不會做類型檢查剧包,而是默默的將所有數(shù)據(jù)都轉(zhuǎn)為 Object

假設(shè)往果,最初我們希望向 List 存儲的是整形數(shù)據(jù)疆液,假設(shè),某個家伙不小心存入了其他數(shù)據(jù)類型陕贮。當(dāng)你試圖從容器中取整形數(shù)據(jù)時堕油,由于 List 當(dāng)成 Object 類型來存儲,你不得不使用類型強(qiáng)制轉(zhuǎn)換飘蚯。在運(yùn)行時馍迄,才會發(fā)現(xiàn) List 中數(shù)據(jù)不存儲一致的問題,這就為程序運(yùn)行帶來了很大的風(fēng)險(無形傷害最為致命)局骤。

而泛型的出現(xiàn)攀圈,解決了類型安全問題。

泛型具有以下優(yōu)點(diǎn):

  • 編譯時的強(qiáng)類型檢查

泛型要求在聲明時指定實(shí)際數(shù)據(jù)類型峦甩,Java 編譯器在編譯時會對泛型代碼做強(qiáng)類型檢查赘来,并在代碼違反類型安全時發(fā)出告警现喳。早發(fā)現(xiàn),早治理犬辰,把隱患扼殺于搖籃嗦篱,在編譯時發(fā)現(xiàn)并修復(fù)錯誤所付出的代價遠(yuǎn)比在運(yùn)行時小。

  • 避免了類型轉(zhuǎn)換

未使用泛型:

List list = new ArrayList();
list.add("hello");
String s = (String) list.get(0);

使用泛型:

List<String> list = new ArrayList<String>();
list.add("hello");
String s = list.get(0);   // no cast
  • 泛型編程可以實(shí)現(xiàn)通用算法

通過使用泛型幌缝,程序員可以實(shí)現(xiàn)通用算法灸促,這些算法可以處理不同類型的集合,可以自定義涵卵,并且類型安全且易于閱讀浴栽。

2. 泛型類型

泛型類型是被參數(shù)化的類或接口。

2.1. 泛型類

泛型類的語法形式:

class name<T1, T2, ..., Tn> { /* ... */ }

泛型類的聲明和非泛型類的聲明類似轿偎,除了在類名后面添加了類型參數(shù)聲明部分典鸡。由尖括號(<>)分隔的類型參數(shù)部分跟在類名后面。它指定類型參數(shù)(也稱為類型變量)T1坏晦,T2萝玷,...和 Tn。

一般將泛型中的類名稱為原型昆婿,而將 <> 指定的參數(shù)稱為類型參數(shù)球碉。

  • 未應(yīng)用泛型的類

在泛型出現(xiàn)之前,如果一個類想持有一個可以為任意類型的數(shù)據(jù)仓蛆,只能使用 Object 做類型轉(zhuǎn)換汁尺。示例如下:

public class Info {
    private Object value;

    public Object getValue() {
        return value;
    }

    public void setValue(Object value) {
        this.value = value;
    }
}
  • 單類型參數(shù)的泛型類
public class Info<T> {
    private T value;

    public Info() { }

    public Info(T value) {
        this.value = value;
    }

    public T getValue() {
        return value;
    }

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

    @Override
    public String toString() {
        return "Info{" + "value=" + value + '}';
    }
}

public class GenericsClassDemo01 {
    public static void main(String[] args) {
        Info<Integer> info = new Info<>();
        info.setValue(10);
        System.out.println(info.getValue());

        Info<String> info2 = new Info<>();
        info2.setValue("xyz");
        System.out.println(info2.getValue());
    }
}
// Output:
// 10
// xyz

在上面的例子中,在初始化一個泛型類時多律,使用 <> 指定了內(nèi)部具體類型,在編譯時就會根據(jù)這個類型做強(qiáng)類型檢查搂蜓。

實(shí)際上狼荞,不使用 <> 指定內(nèi)部具體類型,語法上也是支持的(不推薦這么做)帮碰,如下所示:

public static void main(String[] args) {
    Info info = new Info();
    info.setValue(10);
    System.out.println(info.getValue());
    info.setValue("abc");
    System.out.println(info.getValue());
}

示例說明:

上面的例子丰涉,不會產(chǎn)生編譯錯誤傻唾,也能正常運(yùn)行伪煤。但這樣的調(diào)用就失去泛型類型的優(yōu)勢职烧。

  • 多個類型參數(shù)的泛型類
public class MyMap<K,V> {
    private K key;
    private V value;

    public MyMap(K key, V value) {
        this.key = key;
        this.value = value;
    }

    @Override
    public String toString() {
        return "MyMap{" + "key=" + key + ", value=" + value + '}';
    }
}

public class GenericsClassDemo02 {
    public static void main(String[] args) {
        MyMap<Integer, String> map = new MyMap<>(1, "one");
        System.out.println(map);
    }
}
// Output:
// MyMap{key=1, value=one}
  • 泛型類的類型嵌套
public class GenericsClassDemo03 {
    public static void main(String[] args) {
        Info<String> info = new Info("Hello");
        MyMap<Integer, Info<String>> map = new MyMap<>(1, info);
        System.out.println(map);
    }
}
// Output:
// MyMap{key=1, value=Info{value=Hello}}

2.2. 泛型接口

接口也可以聲明泛型。

泛型接口語法形式:

public interface Content<T> {
    T text();
}

泛型接口有兩種實(shí)現(xiàn)方式:

  • 實(shí)現(xiàn)接口的子類明確聲明泛型類型


public class GenericsInterfaceDemo01 implements Content<Integer> {
    private int text;

    public GenericsInterfaceDemo01(int text) {
        this.text = text;
    }

    @Override
    public Integer text() { return text; }

    public static void main(String[] args) {
        GenericsInterfaceDemo01 demo = new GenericsInterfaceDemo01(10);
        System.out.print(demo.text());
    }
}
// Output:
// 10
  • 實(shí)現(xiàn)接口的子類不明確聲明泛型類型
public class GenericsInterfaceDemo02<T> implements Content<T> {
    private T text;

    public GenericsInterfaceDemo02(T text) {
        this.text = text;
    }

    @Override
    public T text() { return text; }

    public static void main(String[] args) {
        GenericsInterfaceDemo02<String> gen = new GenericsInterfaceDemo02<>("ABC");
        System.out.print(gen.text());
    }
}
// Output:
// ABC

3. 泛型方法

泛型方法是引入其自己的類型參數(shù)的方法骡湖。泛型方法可以是普通方法浦夷、靜態(tài)方法以及構(gòu)造方法肥缔。

泛型方法語法形式如下:

public <T> T func(T obj) {}

是否擁有泛型方法坟岔,與其所在的類是否是泛型沒有關(guān)系纪隙。

泛型方法的語法包括一個類型參數(shù)列表,在尖括號內(nèi)麸锉,它出現(xiàn)在方法的返回類型之前磷脯。對于靜態(tài)泛型方法,類型參數(shù)部分必須出現(xiàn)在方法的返回類型之前檩帐。類型參數(shù)能被用來聲明返回值類型术幔,并且能作為泛型方法得到的實(shí)際類型參數(shù)的占位符。

使用泛型方法的時候湃密,通常不必指明類型參數(shù)诅挑,因?yàn)榫幾g器會為我們找出具體的類型。這稱為類型參數(shù)推斷(type argument inference)勾缭。類型推斷只對賦值操作有效揍障,其他時候并不起作用。如果將一個泛型方法調(diào)用的結(jié)果作為參數(shù)俩由,傳遞給另一個方法毒嫡,這時編譯器并不會執(zhí)行推斷。編譯器會認(rèn)為:調(diào)用泛型方法后幻梯,其返回值被賦給一個 Object 類型的變量兜畸。

public class GenericsMethodDemo01 {
    public static <T> void printClass(T obj) {
        System.out.println(obj.getClass().toString());
    }

    public static void main(String[] args) {
        printClass("abc");
        printClass(10);
    }
}
// Output:
// class java.lang.String
// class java.lang.Integer

泛型方法中也可以使用可變參數(shù)列表

public class GenericVarargsMethodDemo {
    public static <T> List<T> makeList(T... args) {
        List<T> result = new ArrayList<T>();
        Collections.addAll(result, args);
        return result;
    }

    public static void main(String[] args) {
        List<String> ls = makeList("A");
        System.out.println(ls);
        ls = makeList("A", "B", "C");
        System.out.println(ls);
    }
}
// Output:
// [A]
// [A, B, C]

4. 類型擦除

Java 語言引入泛型是為了在編譯時提供更嚴(yán)格的類型檢查,并支持泛型編程碘梢。不同于 C++ 的模板機(jī)制咬摇,Java 泛型是使用類型擦除來實(shí)現(xiàn)的,使用泛型時煞躬,任何具體的類型信息都被擦除了肛鹏。

那么,類型擦除做了什么呢恩沛?它做了以下工作:

  • 把泛型中的所有類型參數(shù)替換為 Object在扰,如果指定類型邊界,則使用類型邊界來替換雷客。因此芒珠,生成的字節(jié)碼僅包含普通的類,接口和方法搅裙。
  • 擦除出現(xiàn)的類型聲明皱卓,即去掉 <> 的內(nèi)容裹芝。比如 T get() 方法聲明就變成了 Object get()List<String> 就變成了 List娜汁。如有必要嫂易,插入類型轉(zhuǎn)換以保持類型安全。
  • 生成橋接方法以保留擴(kuò)展泛型類型中的多態(tài)性存炮。類型擦除確保不為參數(shù)化類型創(chuàng)建新類炬搭;因此,泛型不會產(chǎn)生運(yùn)行時開銷穆桂。

讓我們來看一個示例:

public class GenericsErasureTypeDemo {
    public static void main(String[] args) {
        List<Object> list1 = new ArrayList<Object>();
        List<String> list2 = new ArrayList<String>();
        System.out.println(list1.getClass());
        System.out.println(list2.getClass());
    }
}
// Output:
// class java.util.ArrayList
// class java.util.ArrayList

示例說明:

上面的例子中宫盔,雖然指定了不同的類型參數(shù),但是 list1 和 list2 的類信息卻是一樣的享完。

這是因?yàn)椋?strong>使用泛型時灼芭,任何具體的類型信息都被擦除了。這意味著:ArrayList<Object>ArrayList<String> 在運(yùn)行時般又,JVM 將它們視為同一類型彼绷。

Java 泛型的實(shí)現(xiàn)方式不太優(yōu)雅,但這是因?yàn)榉盒褪窃?JDK5 時引入的茴迁,為了兼容老代碼寄悯,必須在設(shè)計(jì)上做一定的折中。

5. 泛型和繼承

泛型不能用于顯式地引用運(yùn)行時類型的操作之中堕义,例如:轉(zhuǎn)型猜旬、instanceof 操作和 new 表達(dá)式。因?yàn)樗嘘P(guān)于參數(shù)的類型信息都丟失了倦卖。當(dāng)你在編寫泛型代碼時洒擦,必須時刻提醒自己,你只是看起來好像擁有有關(guān)參數(shù)的類型信息而已怕膛。

正是由于泛型時基于類型擦除實(shí)現(xiàn)的熟嫩,所以,泛型類型無法向上轉(zhuǎn)型褐捻。

向上轉(zhuǎn)型是指用子類實(shí)例去初始化父類掸茅,這是面向?qū)ο笾卸鄳B(tài)的重要表現(xiàn)。

img

Integer 繼承了 Object柠逞;ArrayList 繼承了 List倦蚪;但是 List<Interger> 卻并非繼承了 List<Object>

這是因?yàn)楸咂唬盒皖惒]有自己獨(dú)有的 Class 類對象。比如:并不存在 List<Object>.class 或是 List<Interger>.class裁僧,Java 編譯器會將二者都視為 List.class个束。

List<Integer> list = new ArrayList<>();
List<Object> list2 = list; // Erorr

6. 類型邊界

有時您可能希望限制可在參數(shù)化類型中用作類型參數(shù)的類型慕购。類型邊界可以對泛型的類型參數(shù)設(shè)置限制條件。例如茬底,對數(shù)字進(jìn)行操作的方法可能只想接受 Number 或其子類的實(shí)例沪悲。

要聲明有界類型參數(shù),請列出類型參數(shù)的名稱阱表,然后是 extends 關(guān)鍵字殿如,后跟其限制類或接口。

類型邊界的語法形式如下:

<T extends XXX>

示例:

public class GenericsExtendsDemo01 {
    static <T extends Comparable<T>> T max(T x, T y, T z) {
        T max = x; // 假設(shè)x是初始最大值
        if (y.compareTo(max) > 0) {
            max = y; //y 更大
        }
        if (z.compareTo(max) > 0) {
            max = z; // 現(xiàn)在 z 更大
        }
        return max; // 返回最大對象
    }

    public static void main(String[] args) {
        System.out.println(max(3, 4, 5));
        System.out.println(max(6.6, 8.8, 7.7));
        System.out.println(max("pear", "apple", "orange"));
    }
}
// Output:
// 5
// 8.8
// pear

示例說明:

上面的示例聲明了一個泛型方法最爬,類型參數(shù) T extends Comparable<T> 表明傳入方法中的類型必須實(shí)現(xiàn)了 Comparable 接口涉馁。

類型邊界可以設(shè)置多個,語法形式如下:

<T extends B1 & B2 & B3>

?? 注意:extends 關(guān)鍵字后面的第一個類型參數(shù)可以是類或接口爱致,其他類型參數(shù)只能是接口烤送。

示例:

public class GenericsExtendsDemo02 {
    static class A { /* ... */ }
    interface B { /* ... */ }
    interface C { /* ... */ }
    static class D1 <T extends A & B & C> { /* ... */ }
    static class D2 <T extends B & A & C> { /* ... */ } // 編譯報錯
    static class E extends A implements B, C { /* ... */ }

    public static void main(String[] args) {
        D1<E> demo1 = new D1<>();
        System.out.println(demo1.getClass().toString());
        D1<String> demo2 = new D1<>(); // 編譯報錯
    }
}

7. 類型通配符

類型通配符一般是使用 ? 代替具體的類型參數(shù)。例如 List<?> 在邏輯上是 List<String> 糠悯,List<Integer> 等所有 List<具體類型實(shí)參> 的父類帮坚。

7.1. 上界通配符

可以使用上界通配符來縮小類型參數(shù)的類型范圍。

它的語法形式為:<? extends Number>

public class GenericsUpperBoundedWildcardDemo {
    public static double sumOfList(List<? extends Number> list) {
        double s = 0.0;
        for (Number n : list) {
            s += n.doubleValue();
        }
        return s;
    }

    public static void main(String[] args) {
        List<Integer> li = Arrays.asList(1, 2, 3);
        System.out.println("sum = " + sumOfList(li));
    }
}
// Output:
// sum = 6.0

7.2. 下界通配符

下界通配符將未知類型限制為該類型的特定類型或超類類型互艾。

?? 注意:上界通配符和下界通配符不能同時使用试和。

它的語法形式為:<? super Number>

public class GenericsLowerBoundedWildcardDemo {
    public static void addNumbers(List<? super Integer> list) {
        for (int i = 1; i <= 5; i++) {
            list.add(i);
        }
    }

    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        addNumbers(list);
        System.out.println(Arrays.deepToString(list.toArray()));
    }
}
// Output:
// [1, 2, 3, 4, 5]

7.3. 無界通配符

無界通配符有兩種應(yīng)用場景:

  • 可以使用 Object 類中提供的功能來實(shí)現(xiàn)的方法。
  • 使用不依賴于類型參數(shù)的泛型類中的方法纫普。

語法形式:<?>

public class GenericsUnboundedWildcardDemo {
    public static void printList(List<?> list) {
        for (Object elem : list) {
            System.out.print(elem + " ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        List<Integer> li = Arrays.asList(1, 2, 3);
        List<String> ls = Arrays.asList("one", "two", "three");
        printList(li);
        printList(ls);
    }
}
// Output:
// 1 2 3
// one two three

7.4. 通配符和向上轉(zhuǎn)型

前面阅悍,我們提到:泛型不能向上轉(zhuǎn)型。但是局嘁,我們可以通過使用通配符來向上轉(zhuǎn)型溉箕。

public class GenericsWildcardDemo {
    public static void main(String[] args) {
        List<Integer> intList = new ArrayList<>();
        List<Number> numList = intList;  // Error

        List<? extends Integer> intList2 = new ArrayList<>();
        List<? extends Number> numList2 = intList2;  // OK
    }
}

擴(kuò)展閱讀:Oracle 泛型文檔

8. 泛型的約束

Pair<int, char> p = new Pair<>(8, 'a');  // 編譯錯誤
public static <E> void append(List<E> list) {
    E elem = new E();  // 編譯錯誤
    list.add(elem);
}
public class MobileDevice<T> {
    private static T os; // error

    // ...
}
public static <E> void rtti(List<E> list) {
    if (list instanceof ArrayList<Integer>) {  // 編譯錯誤
        // ...
    }
}
List<Integer> li = new ArrayList<>();
List<Number>  ln = (List<Number>) li;  // 編譯錯誤
List<Integer>[] arrayOfLists = new List<Integer>[2];  // 編譯錯誤
// Extends Throwable indirectly
class MathException<T> extends Exception { /* ... */ }    // 編譯錯誤

// Extends Throwable directly
class QueueFullException<T> extends Throwable { /* ... */ // 編譯錯誤
public static <T extends Exception, J> void execute(List<J> jobs) {
    try {
        for (J job : jobs)
            // ...
    } catch (T e) {   // compile-time error
        // ...
    }
}
public class Example {
    public void print(Set<String> strSet) { }
    public void print(Set<Integer> intSet) { } // 編譯錯誤
}

9. 泛型最佳實(shí)踐

9.1. 泛型命名

泛型一些約定俗成的命名:

  • E - Element
  • K - Key
  • N - Number
  • T - Type
  • V - Value
  • S,U,V etc. - 2nd, 3rd, 4th types

9.2. 使用泛型的建議

  • 消除類型檢查告警
  • List 優(yōu)先于數(shù)組
  • 優(yōu)先考慮使用泛型來提高代碼通用性
  • 優(yōu)先考慮泛型方法來限定泛型的范圍
  • 利用有限制通配符來提升 API 的靈活性
  • 優(yōu)先考慮類型安全的異構(gòu)容器

10. 小結(jié)

img

11. 參考資料

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末肴茄,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子但指,更是在濱河造成了極大的恐慌寡痰,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件棋凳,死亡現(xiàn)場離奇詭異拦坠,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)剩岳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進(jìn)店門贞滨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事晓铆∩琢迹” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵骄噪,是天一觀的道長尚困。 經(jīng)常有香客問我,道長链蕊,這世上最難降的妖魔是什么事甜? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮滔韵,結(jié)果婚禮上逻谦,老公的妹妹穿的比我還像新娘。我一直安慰自己奏属,他們只是感情好跨跨,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著囱皿,像睡著了一般勇婴。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上嘱腥,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天耕渴,我揣著相機(jī)與錄音,去河邊找鬼齿兔。 笑死橱脸,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的分苇。 我是一名探鬼主播添诉,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼医寿!你這毒婦竟也來了栏赴?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤靖秩,失蹤者是張志新(化名)和其女友劉穎须眷,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體沟突,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡花颗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了惠拭。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片扩劝。...
    茶點(diǎn)故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出棒呛,到底是詐尸還是另有隱情葡公,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布条霜,位于F島的核電站,受9級特大地震影響涵亏,放射性物質(zhì)發(fā)生泄漏宰睡。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一气筋、第九天 我趴在偏房一處隱蔽的房頂上張望拆内。 院中可真熱鬧,春花似錦宠默、人聲如沸麸恍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽抹沪。三九已至,卻和暖如春瓤球,著一層夾襖步出監(jiān)牢的瞬間融欧,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工卦羡, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留噪馏,地道東北人。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓绿饵,卻偏偏與公主長得像欠肾,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子拟赊,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評論 2 345

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

  • 說來慚愧刺桃,雖然平時經(jīng)常會使用到一些泛型類,但是卻一直沒有深入地去了解過泛型機(jī)制要门。今天開始學(xué)習(xí)記錄泛型機(jī)制相關(guān)的知識...
    怡紅快綠閱讀 524評論 0 1
  • 簡介 泛型的意思就是參數(shù)化類型虏肾,通過使用參數(shù)化類型創(chuàng)建的接口、類欢搜、方法封豪,可以指定所操作的數(shù)據(jù)類型。比如:可以使用參...
    零度沸騰_yjz閱讀 3,306評論 1 15
  • [TOC] 深入理解 Java 泛型 概述 泛型的本質(zhì)是參數(shù)化類型炒瘟,通常用于輸入?yún)?shù)吹埠、存儲類型不確定的場景。相比于...
    albon閱讀 5,289評論 0 7
  • 由于下周要迎接我人生第一次走上講臺對大學(xué)生講課的日子的到來粘都,這幾天我暫時放下了《科技想要什么》的閱讀,開始復(fù)習(xí)一下...
    鐵家軍貝貝閱讀 449評論 3 0
  • 在轟轟烈烈的愛情刷袍,終會隨時間流逝慢慢減弱翩隧。誰還記得當(dāng)時的山盟海誓,那都是刷孩子的把戲罷了呻纹!最終都離不開堆生,慢慢從熱戀...
    我是老大stupid閱讀 431評論 0 0