Java泛型使用示例整理

Java泛型使用示例整理

目標

Java泛型編程是JDK1.5版本后引入的。泛型讓編程人員能夠使用類型抽象,通常用于集合里面。本文旨在整理一些泛型的用法。

用法

泛型分兩部分。一部分是泛型類和方法的定義。另一部分是泛型類和方法的使用。

定義篇

類定義時,使用泛型

在定義類的時候,我們可以使用泛型。如下代碼:

class Demo <T> {
    T field;
    
    public void setFiled(T field) {
        this.field = field;
    }
    
    public T getField() {
        return field;
    }
}

public class Test {
    
    public static void main (String[] args) throws java.lang.Exception
    {
        Demo<String> demo = new Demo<String>();
        demo.setFiled("www.bo56.com");
        System.out.println(demo.getField());
    }
}

類名后面增加<T>,說明是泛型類。T可以視為類型的占位符。泛型類的代碼就可以使用這個占位符T。

無參數方法定義時,使用泛型

無論在泛型類,還是普通類中,我們都可以再方法中使用泛型。

import java.util.ArrayList;
import java.util.List;

class Demo {
    
    public <T> List<T> newArrayList() {
        return new ArrayList<T>();
    }
}

public class Test {
    
    public static void main (String[] args) throws java.lang.Exception
    {
        Demo demo = new Demo();
        List<String> list = demo.newArrayList();
        list.add("www.bo56.com");
        list.add("bo56.com");
        //list.add(1); 報錯。只能添加String
        for (String str:list) {
            System.out.println(str);
        }
    }
}

方法的返回值前面,修飾符后面增加<T>,表示為泛型方法。這樣,就可以在方法的代碼中使用T代表類型。
沒有參數的泛型方法,類型的確定,是根據等號左邊的類型推導泛型的最終類型。

有參數方法定義時,使用泛型

class Demo {
    
    public <T> void showClass(T t) {
        System.out.println(t.getClass());
    }
}

public class Test {
    
    public static void main (String[] args) throws java.lang.Exception
    {
        Demo demo = new Demo();
        demo.showClass("123");
        demo.showClass(123);
    }
}

有參數的泛型方法,類型的確定,是根據參數類型自動推導。

方法定義時,使用通配符 ?

import java.util.ArrayList;
import java.util.List;

class Demo {
    
    public void show(List<?> list) {
        list.add(null);
        //list.add(123); 編譯錯誤
        for (Object object:list) {
            System.out.println(object);
        }
    }
}

public class Test {
    
    public static void main (String[] args) throws java.lang.Exception
    {
        Demo demo = new Demo();
        List<String> listStr = new ArrayList<String>();
        listStr.add("abc");
        demo.show(listStr);
        List<Long> listLong = new ArrayList<Long>();
        listLong.add(123L);
        demo.show(listLong);
    }
}

1、只能往集合中add null。
2、因為集合中的類型不確定。因此,為了安全,轉換為Object。

類或者方法定義時,使用通配符 <T extends Number>

class Demo {
    
    public <T extends Number> void showClass(T t) {
        System.out.println(t.getClass());
    }
}

public class Test {
    
    public static void main (String[] args) throws java.lang.Exception
    {
        Demo demo = new Demo();
        demo.showClass(123);
        demo.showClass(123f);
        demo.showClass(123L);
        // demo.showClass("123"); 有錯誤 參數的類型,只能是 Number類型或者其子類
    }
}

<T extends Number> 表示傳入的類型必須是Number或者其子類型。

使用篇

指定固定的類型

import java.util.ArrayList;
import java.util.List;

public class Test {
    
    public static void main (String[] args) throws java.lang.Exception
    {
        List<Long> list = new ArrayList<Long>();
        //List<Number> listN = new ArrayList<Long>(); 編譯錯誤。List<Number> 并不是 ArrayList<Long> 的父類。
    }
}

如果變量聲明時,為泛型指定的類型為固定類型。如List<Long>,就是為泛型指定的類型為Long。那么后續在給變量賦值時,指定的變量也得為這個類型。如 ArrayList<Long>(),指定的也是Long。
對于泛型來說,Long是Number的子類。但是,List<Long>并不是List<Number>的子類。

使用通配符 ?

import java.util.ArrayList;
import java.util.List;

class Food {}

class Fruit extends Food {}

class Apple extends Fruit {}

public class Test {
    
    public static void main (String[] args) throws java.lang.Exception
    {
        List<?> list = new ArrayList<Fruit>();
        //list.add(new Food()); 編譯錯誤
        //list.add(new Fruit()); 編譯錯誤
        //list.add(new Apple()); 編譯錯誤
        list.add(null);
        //Food food = list.get(0);
        //Fruit fruit = list.get(0);
        //Apple apple = list.get(0);
        Object object = list.get(0);
    }
}

1、只能添加null。
2、獲取的值只能賦值給Object類型。
因為通配符?表示該集合存儲的元素類型未知,可以是任何類型。往集合中加入元素需要是一個未知元素類型的子類型,正因為該集合存儲的元素類型未知,所以我們沒法向該集合中添加任何元素。唯一的例外是null,因為null是所有類型的子類型,所以盡管元素類型不知道,但是null一定是它的子類型。

使用上界通配符 <? extends Fruit>

import java.util.ArrayList;
import java.util.List;

class Food {}

class Fruit extends Food {}

class Apple extends Fruit {}

public class Test {
    
    public static void main (String[] args) throws java.lang.Exception
    {
        List<? extends Fruit> list = new ArrayList<Fruit>();
        // List<? extends Fruit> listA = new ArrayList<Food>(); 編譯錯誤。不能為父類。
        List<? extends Fruit> listN = new ArrayList<Apple>();
        listN.add(null);
        //listN.add(123); 不能add
        Fruit fruit = listN.get(0);
        Food food = listN.get(0);
        //Apple apple = listN.get(0); 編譯錯誤。get獲取的值,只能給父類
        listN.remove(0);
    }
}

上界通配符,一般用于讀取的場景。
1、為泛型指定的類型只能是Fruit類型或者其子類。
2、只能為其列表添加null。
3、get方法獲取的值只能賦值給Fruit類或者其超類。

使用下界通配符 <? super Fruit>

import java.util.ArrayList;
import java.util.List;

class Food {}

class Fruit extends Food {}

class Apple extends Fruit {}

public class Test {
    
    public static void main (String[] args) throws java.lang.Exception
    {
        List<? super Fruit> list = new ArrayList<Fruit>();
        List<? super Fruit> listA = new ArrayList<Food>(); 
        //List<? super Fruit> listN = new ArrayList<Apple>(); 編譯錯誤,不能為子類
        listA.add(new Fruit());
        //listA.add(new Food()); 編譯錯誤,不能為父類。
        listA.add(new Apple());
        Object object = listA.get(0);
        //Fruit fruit = listA.get(0);編譯錯誤。
        //Food food = listA.get(0);編譯錯誤。
        //Apple apple = listA.get(0); 編譯錯誤。
    }
}

下界通配符,一般用于寫入的場景。
1、為泛型指定的類型必須為Fruit,或者其超類。
2、可以為其列表添加任意Fruit類型,或者其子類。
3、get方法獲取的類型,只能賦值給Object類型。

邊界通配符總結

邊界通配符總結
如果你想從一個數據類型里獲取數據,使用 ? extends 通配符
如果你想把對象寫入一個數據結構里,使用 ? super 通配符
如果你既想存,又想取,那就別用通配符。

注意

泛型類型是被所有調用共享的

import java.util.ArrayList;
import java.util.List;

public class Test {
    
    public static void main (String[] args) throws java.lang.Exception
    {
        List<String>l1 = new ArrayList<String>();  
        List<Integer>l2 = new ArrayList<Integer>();  
        System.out.println(l1.getClass() == l2.getClass()); //True  
    }
}

所有泛型類的實例都共享同一個運行時類,類型參數信息會在編譯時被擦除。因此考慮如下代碼,雖然ArrayList<String>和ArrayList<Integer>類型參數不同,但是他們都共享ArrayList類,所以結果會是true。

instanceof

import java.util.ArrayList;
import java.util.Collection;

public class Test {
    
    public static void main (String[] args) throws java.lang.Exception
    {
        Collection cs = new ArrayList<String>();  
        if (cs instanceof Collection<String>){}// compile error.如果改成instanceof Collection<?>則不會出錯。  
    }
}

不能對確切的泛型類型使用instanceOf操作。如下面的操作是非法的,編譯時會出錯。

泛型數組問題

import java.util.ArrayList;
import java.util.List;

public class Test {
    
    public static void main (String[] args) throws java.lang.Exception
    {
        List<String>[] lsa = new ArrayList<String>[10]; //compile error.
    }
}

不能創建一個確切泛型類型的數組。


import java.util.ArrayList;
import java.util.List;

public class Test {
    
    public static void main (String[] args) throws java.lang.Exception
    {
        List<?>[] lsa = new ArrayList<?>[10]; // ok, array of unbounded wildcard type  
    }
}

能創建帶通配符的泛型數組.

參考

http://qiemengdao.iteye.com/blog/1525624
http://www.cnblogs.com/iyangyuan/archive/2013/04/09/3011274.html

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,546評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,570評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,505評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,017評論 1 313
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,786評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,219評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,287評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,438評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,971評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,796評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,995評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,540評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,230評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,918評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,697評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,991評論 2 374

推薦閱讀更多精彩內容

  • 前言 泛型(Generics)的型變是Java中比較難以理解和使用的部分,“神秘”的通配符,讓我看了幾遍《Java...
    珞澤珈群閱讀 7,885評論 12 51
  • 國家電網公司企業標準(Q/GDW)- 面向對象的用電信息數據交換協議 - 報批稿:20170802 前言: 排版 ...
    庭說閱讀 11,056評論 6 13
  • 開發人員在使用泛型的時候,很容易根據自己的直覺而犯一些錯誤。比如一個方法如果接收List作為形式參數,那么如果嘗試...
    時待吾閱讀 1,068評論 0 3
  • 人倒著走 車子倒著開 時光倒著奔跑 你倒著回到她的身邊 公司兩個月前新來了一個運營總監,30歲出頭,超嚴肅的范。身...
    方不見閱讀 1,061評論 4 23
  • 【1】忠誠 單位不一定挽留有能力的員工,但對一個忠心耿耿的人,不會有領導愿意讓他走,他會成為單位這個鐵打營盤中最長...
    立信會計閱讀 450評論 0 0