泛型學習

想要封裝一個好用的網(wǎng)絡框架灌砖,肯定繞不過泛型這關(guān)。
最近遇到網(wǎng)絡請求相關(guān)問題泣特,網(wǎng)上也沒有和我相同的需求,只能自己動手了挑随,順便學習學習json泛型状您,先學習泛型

[TOC]

個人認知:泛型的作用

為了讓錯誤提前到編譯期發(fā)現(xiàn),使程序更安全

參考《Effective Java》 第五章泛型

第23條

raw type

List<E> 對應的raw typeList兜挨,raw type 可以直接使用膏孟,但是我們不應該這么做,這只是為了兼容問題做的保留拌汇,如果使用raw type失掉了泛型在安全性和表述性方面的所有優(yōu)勢

Gsonnew Type(){}就是這樣柒桑,不要去這樣使用,使用時明確類型:new Type<Object>(){} 指定泛型

使用raw type<Object>的區(qū)別噪舀,(ListList<Object> 的區(qū)別)前者逃避了類型檢查

{//代碼示例...
List<String> list = new ArrayList<String>();
add1(list, 42);
add2(list, 42);//Error: 不兼容的類型: List<String>無法轉(zhuǎn)換為List<Object>
}

void add1(List list, Object o) {
list.add(o);
}

void add2(List<Object> list, Object o) {
list.add(o);
}

無限制通配符

泛型Set<E>的無限制通配符類型為Set<?> 讀作"某個類型的集合"魁淳。

通配符是類型安全的,raw type類型不安全

void add2(List<?> list, Object o) {
  list.add("");
   /*Error:(26, 13) 錯誤: 對于add(String), 找不到合適的方法
    方法 Collection.add(CAP#1)不適用
    (參數(shù)不匹配; String無法轉(zhuǎn)換為CAP#1)*/
}

raw type 可以很容易的破壞集合的約束條件与倡,而通配符則會限制這種情況的發(fā)生(null除外)界逛, 可以配合泛型方法generic method 和有限制的通配符類型bounded wildcard type 使用

快速回顧

  • Set<Object> 是個參數(shù)化類型,表示可以包含任何對象類型的一個集合
  • Set<?> 則是一個通配符類型纺座,表示只能包含某種未知對象類型的一個集合
  • Set則是一個原生態(tài)類型raw type息拜,它脫離了泛型系統(tǒng),不安全比驻。
  • 參數(shù)化類型 : List<String>
  • 實際類型參數(shù):String>
  • 泛型:List<E>
  • 形式類型參數(shù):E
  • 無限制通配符類型:List<?>
  • 原生態(tài)類型:List
  • 有限制類型參數(shù):<E extends Number>
  • 遞歸類型限制:<T extends Comparable<T>
  • 有限制通配符類型:List <? extends Number>
  • 泛型方法:static <E> List<E> func(E[] e)
  • 類型令牌:String.class

第24條

@SuppressWarnings 注解使用

  1. 也可以使用在變量上
  2. 不能直接在return 上使用该溯,這時創(chuàng)建局部變量接受返回值,然后注解

第25條 列表優(yōu)先于數(shù)組

  • 第一個區(qū)別:數(shù)組是協(xié)變(covariant) 别惦,泛型是不可變(invariant)狈茉。

    //數(shù)組,編譯時合法
    Object[] objects = new Long[1]; //Long 是Object的子類
    objects[0] = "aa";//運行時會拋出異常 ArrayStroeException
    
    //集合掸掸,編譯時無法通過
    List<Object> list = new ArrayList<Long>();//無法編譯通過氯庆,類型不匹配
    list.add("aa");
    
  • 第二個區(qū)別:數(shù)組是具體化(reified) 運行時才知道并檢查類型蹭秋,泛型是通過擦除(erasure)來實現(xiàn)的,編譯時就可以明確

創(chuàng)建泛型堤撵、參數(shù)化類型或者類型參數(shù)的數(shù)組是非法的仁讨。new List<E>[]new List<String>[]实昨、new E[] 都是不合法的洞豁。

如果是合法的話,將創(chuàng)建出來“列表數(shù)組”保存到一個Objcect數(shù)組荒给,然后使用這個數(shù)組修改“列表數(shù)組”的類型丈挟,這時候再從原始的容器中取出內(nèi)容就會發(fā)生錯誤

技術(shù)角度來說,像E志电、List<E>List<String> 這樣的類型應該稱作不可具體化(nonreifiable)曙咽,

不可具體化(nonreifiable),指其運行時表示法包含的信息比它編譯時表示法包含的信息更少的類型

唯一可具體化的參數(shù)化類型是無限制的通配符類型

第27條 優(yōu)先考慮泛型方法

將含有警告的raw type 方法修改為泛型方法

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

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

方法的局限性在于挑辆,三個集合的類型(兩個輸入?yún)?shù)和一個返回值)必須全部相同例朱。

利用有限制的通配符類型,讓這個方法變得更加靈活

泛型方法的一個顯著特性是鱼蝉,無需明確指定類型參數(shù)的值洒嗤,不像調(diào)用泛型構(gòu)造器的時候是必須指定的。編譯器通過檢查方法參數(shù)的類型來計算類型參數(shù)的值蚀乔。

通過某個包含該類型參數(shù)本身的表達式來限制類型參數(shù)是允許的烁竭。這就是遞歸類型限制 。遞歸類型限制最普遍的用途與Comparable接口有關(guān)吉挣,他定義類型的自然順序:

public interface Comparable<T> {
    int compareTo(T o);
}

類型參數(shù)T 定義的類型派撕,可以與實現(xiàn)Comparable<T>的類型的元素進行比較。

下面是如何表達這種約束條件的一個示例

public static <T extends Comparable<T>> T max(List<T> list){...}

類型限制<T extends Comparable<T>> 睬魂,可以讀作"針對可以與自身進行比較的每個類型T"

//示例
public static <T extends Comparable<T>> T max(List<T> list) {
  Iterator<T> iterator = list.iterator();
  T result = iterator.next();
  while (iterator.hasNext()) {
    T t = iterator.next();
    if (t.compareTo(result)>0) {
      result = t;
    }
  }
  return result;
}

第28條 利用有限制通配符來提升API的靈活性

<? extends E>

為在剛剛的Stack 類添加一個新方法pushAll(Iterable<E> iterable)

public void pushAll(Iterable<E> iterable) {
  for (E e : iterable) {
 push(e);
  }
}
Stack<Number> numberStack = new Stack<>();
Iterable<Integer> integers = new ArrayList<>();
numberStack.pushAll(integers);//此時編譯不通過

pushAll(Iterable<E> iterable)修改為Iterable<? extends E> iterable

此時可以編譯通過

<? super E>

添加一個新方法

public void popAll(Collection<E> collection) {
  while (!isEmpty())
    collection.add(pop());
}
Stack<Number> numberStack1 = new Stack<>();
Collection<Object> objects = new ArrayList<>();
numberStack.popAll(objects);//此時編譯不通過

popAll(Collection<E> collection)修改為popAll(Collection<? super E> collection)

此時可以編譯通過

為了獲得最大限度的靈活性终吼,要在表示生產(chǎn)者或者消費者的輸入?yún)?shù)上使用通配符類型

助記符 PECS

PECS 表示producer-extends consumer-super

如果表示生產(chǎn)者就使用<? extends T>,如果表示消費者就使用<? super T>

如果使用得當氯哮,通配符類型對于類的用戶來說幾乎是無形的际跪。它們使方法能夠接受它們應該接受的參數(shù),并拒絕那些該拒絕的參數(shù)喉钢。如果類的用戶必須考慮通配符類型姆打,類的API或許就會出錯

//示例
<E> E reduce(List<E> list, Function<E> function, E initVal) {...}
//修改后
<E> E reduce2(List<? extends E> list, Function<E> function, E initVal) {...}
//示例2
public static <E> Set<E> union(Set<E> s1, Set<E> s2) {...}
//修改后 ,返回類型不要含有通配符
public static <E> Set<E> union(Set<? extends E> s1, Set<? extends E> s2) {... }
//兩者的區(qū)別在于
Set<Integer> integers = new HashSet<>();
Set<Double> doubles = new HashSet<>();
//使用通配符的方法可以通過一個【顯示的類型參數(shù)】來告訴要使用哪種類型
Set<Number> numbers = Math2.<Number>union(integers, doubles);

修改第27條中的max方法

public static <T extends Comparable<T>> T max(List<T> list)
//修改后, 應用PECS轉(zhuǎn)換兩次
public static <T extends Comparable<? super T>> T max(List<? extends T> list)
//同時修改   Iterator<? extends T> iterator = list.iterator();

還有一個與通配符有關(guān)的話題值得探討肠虽。類型參數(shù)和通配符之間具有雙重性幔戏,許多方法都可以利用其中一個或者另一個進行聲明。

//示例
public static <E> void swap(List<E> list ,int i ,int j);
public static void swap(List<?> list ,int i ,int j);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末税课,一起剝皮案震驚了整個濱河市闲延,隨后出現(xiàn)的幾起案子痊剖,更是在濱河造成了極大的恐慌,老刑警劉巖垒玲,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件陆馁,死亡現(xiàn)場離奇詭異,居然都是意外死亡合愈,警方通過查閱死者的電腦和手機叮贩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來佛析,“玉大人妇汗,你說我怎么就攤上這事∷的” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵寞焙,是天一觀的道長储狭。 經(jīng)常有香客問我,道長捣郊,這世上最難降的妖魔是什么辽狈? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮呛牲,結(jié)果婚禮上刮萌,老公的妹妹穿的比我還像新娘。我一直安慰自己娘扩,他們只是感情好着茸,可當我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著琐旁,像睡著了一般涮阔。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上灰殴,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天敬特,我揣著相機與錄音,去河邊找鬼牺陶。 笑死伟阔,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的掰伸。 我是一名探鬼主播皱炉,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼碱工!你這毒婦竟也來了娃承?” 一聲冷哼從身側(cè)響起奏夫,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎历筝,沒想到半個月后酗昼,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡梳猪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年麻削,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片春弥。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡呛哟,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出匿沛,到底是詐尸還是另有隱情扫责,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布逃呼,位于F島的核電站鳖孤,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏抡笼。R本人自食惡果不足惜苏揣,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望推姻。 院中可真熱鬧平匈,春花似錦、人聲如沸藏古。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拧晕。三九已至弟跑,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間防症,已是汗流浹背孟辑。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蔫敲,地道東北人饲嗽。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像奈嘿,于是被迫代替她去往敵國和親貌虾。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,877評論 2 345

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

  • 簡單實用 泛型就是參數(shù)化類型裙犹,可以將類型當作參數(shù)傳遞給一個類或者是方法尽狠。 假設 Cache 能夠存取任何類型的值:...
    ccccccal閱讀 192評論 0 0
  • 原生態(tài)類型 在沒有泛型之前衔憨,如果我們要維護一個價格列表: 當有人插入非法數(shù)據(jù)時,編譯也不會報異常 但是執(zhí)行的時候袄膏,...
    小小浪把_Dont_know拍閱讀 218評論 0 0
  • 泛型類定義與使用 定義泛型//定義 class Point<T>{// 此處可以隨便寫標識符號 pr...
    陌上疏影涼閱讀 320評論 0 0
  • 我不知道自己是否會生女兒践图,暫且當是吧。 我未來的女兒是我的好朋友好閨蜜沉馆。在她還在很小很小的時候码党,就教會了我很多的事...
    laBonita閱讀 162評論 2 2
  • 2017年的暑假,我到羅馬尼亞阿拉德當了一回志愿者斥黑,這次的經(jīng)歷可以說是終生難忘揖盘,有了許許多多的第一次,第一次一個人...
    molli閱讀 814評論 0 0