摘要:通過方法返回值來確定具體泛型類型。泛型類定義的泛型聲明在整個類定義中都有效。相同類型參數(shù)的泛型類的關(guān)系取決于泛型類自身的繼承體系結(jié)構(gòu)。
首先,明確一點的是:java的泛型是擦除的。
即系,泛型只存在于編譯時,編譯后都是Object類型(也不全是,見后面解析,運行時也能獲得一定的泛型信息)。
泛型對于Java編程的作用:
(
最主要:增加編譯時的類型安全檢查。
其次:你說它能做到抽取不同類型的共同代碼的話,可能就只適用于容器類。容器類中適合存放不同的類型,而且不管存放的類型是什么都適用。但是要求存放的類型是要一致。
)
泛型的所做的實質(zhì)工作:
編譯時,在泛型類的入口(如:方法參數(shù)),會進(jìn)行編譯時的類型安全檢查(子類,父類關(guān)系檢查,是否是安全的向上轉(zhuǎn)型)。
而且編譯器會在編譯時增加語法糖,對泛型類的出口(如: 返回值),編譯器會對字節(jié)碼自動增加類型轉(zhuǎn)換的代碼。
編譯前的泛型類:
public static void main(String[] args) { Mapmap = new HashMap (); map.put("hello", "你好"); map.put("how are you?", "吃了沒?"); System.out.println(map.get("hello")); System.out.println(map.get("how are you?")); }
把上面的代碼編譯成class文件后,再用字節(jié)碼反編譯工具進(jìn)行反編譯后:
public static void main(String[] args) { Map map = new HashMap(); map.put("hello", "你好"); map.put("how are you?", "吃了沒?"); System.out.println((String) map.get("hello")); System.out.println((String) map.get("how are you?")); }
在運行時,
(重要!)總結(jié):擦除法所謂的擦除,僅僅是對字節(jié)碼中方法中的方法體的Code屬性中的字節(jié)碼進(jìn)行擦除(即方法體中的代碼沒有泛型),但是實際上的元數(shù)據(jù)(類定義,方法定義,字段定義)的Signature中還是保存著 具體參數(shù)化類型 信息。
上面描述的具體參數(shù)化類型信息,可以供用戶查詢得到。
(如:類定義MyList implements List
在編譯時,
我們知道編譯器時掌握泛型信息的。
那么問題剩下: 編譯器如何依據(jù)泛型信息在編譯時進(jìn)行類型安全檢查。
第一點:
在(泛型類定義,泛型接口方法和函數(shù))定義中,編譯器如何確定具體泛型類型。
對于泛型類定義:
(通常一個變量引用的聲明類型來決定,或者實例化對象時指定)
如果泛型類定義是(如:public interface Map
現(xiàn)在有一個變量聲明,Map
又如,有一個實例化對象 new HashMap
對于 泛型接口方法和函數(shù)(包括實例化對象時的構(gòu)造函數(shù)) :
編譯器確定具體泛型類型是通過方法簽名中的 方法參數(shù) 或者 方法返回值。
(1)通過 方法參數(shù) 來確定 具體泛型類型。
(2)通過 方法返回值 來確定 具體泛型類型。
(3)構(gòu)造函數(shù)
java.util.ArrayList.ArrayList(Collection extends E> c)
第二點:
在(泛型類定義,泛型接口方法和函數(shù))中的泛型聲明在編譯器中的作用域(泛型聲明的影響范圍)和對應(yīng)關(guān)系。
泛型類定義的泛型聲明在整個類定義中都有效。
如果在泛型類定義中有泛型聲明,(如:public interface Map
泛型接口方法和函數(shù)的泛型聲明在方法體和方法簽名有效。如果在泛型接口方法和函數(shù)上聲明了自己的泛型聲明則獨立開辟一個新的作用域,與類定義的泛型聲明區(qū)分開。
public class CopyOfGenericCollection { // 在泛型接口方法和函數(shù)中新開辟一個泛型聲明作用域 // 這里的泛型聲明A和B,與類定義中的A和B 是沒有關(guān)系。 public Map unmodifiableMap1(Map super A, ? extends B> m) { return null; } // 沿用泛型類定義的泛型聲明 public Map unmodifiableMap2(Map super A, ? extends B> m) { return null; } }
// 測試
public class Test { public static void main(String[] args) { CopyOfGenericCollectionextend = new CopyOfGenericCollection (); // 可以看到map1變量的類型為Map
最后
編譯的類型安全檢查,最基本的就是類型轉(zhuǎn)換,我們知道類型向上轉(zhuǎn)型是安全。
所以要使包含泛型的代碼中通過編譯器的編譯,我們要求賦值語句的都是,子類賦值父類,這就引入了 泛型系統(tǒng)的類型繼承關(guān)系。
相同類型參數(shù)的泛型類的關(guān)系取決于泛型類自身的繼承體系結(jié)構(gòu)。
即List
當(dāng)泛型類的類型聲明中使用了通配符的時候, 其子類型可以在兩個維度上分別展開。
如對Collection extends Number>來說,其子類型可以在Collection這個維度上展開,即List extends Number>和Set extends Number>等;
也可以在Number這個層次上展開,即Collection
如此循環(huán)下去,ArrayList
如果泛型類中包含多個類型參數(shù)(如:Map),則對于每個類型參數(shù)分別應(yīng)用上面的規(guī)則。
Collection extends Number> col_number = null; List extends Number> list_number = null; Set extends Number> set_number = null; Collectioncol_double = null; Collection col_integer = null; HashSet hashSet_double = null; ArrayList arrayList_integer = null; col_number = list_number; col_number = set_number; col_number = col_double; col_number = col_integer; col_number = hashSet_double; col_number = arrayList_integer; Collection super Number> col_number_super = null; Collection super List> col_list_super = null; Collection col_col_super = null; Collection col_arrayList_super = null; // col_number_super = col_number;// compile error // col_number = col_number_super;// compile error col_number_super = (Collection super Number>) col_number; col_number = (Collection extends Number>) col_number_super; col_list_super = col_col_super; // col_col_super = col_list_super; // compile error // col_list_super = col_arrayList_super; // compile error Map extends Number, ? extends List> map_generic = null; Map map_number_list = null; Map map_integer_arrayList = null; Map map_integer_col = null; Map super Number, ? super List> map_generic_super = null; map_generic = map_number_list; map_generic = map_integer_arrayList; // map_generic = map_integer_col; // compile error // map_generic = map_generic_super; // compile error // map_generic_super = map_generic; // compile error Map super List, ? super List> map_generic_list_super = null; Map map_generic_col_super = null; map_generic_list_super = map_generic_col_super; // map_generic_col_super = map_generic_list_super; // compile error
下面是摘錄自知乎的見解:
https://www.zhihu.com/questio...
PECS原則
最后看一下什么是PECS(Producer Extends Consumer Super)原則,已經(jīng)很好理解了:
1.頻繁往外讀取內(nèi)容的,適合用上界Extends。
2.經(jīng)常往里插入的,適合用下界Super。
? 如果要從集合中讀取類型T的數(shù)據(jù),并且不能寫入,可以使用 ? extends 通配符;(Producer Extends)
? 如果要從集合中寫入類型T的數(shù)據(jù),并且不需要讀取,可以使用 ? super 通配符;(Consumer Super)
? 如果既要存又要取,那么就不要使用任何通配符。
什么是上界?
下面代碼就是“上界通配符(Upper Bounds Wildcards)”:
Plate<? extends Fruit>
翻譯成人話就是:一個能放水果以及一切是水果派生類的盤子。再直白點就是:啥水果都能放的盤子。
Plate<? extends Fruit>是Plate
在這個體系中,上界通配符 “Plate<? extends Fruit>” 覆蓋下圖中藍(lán)色的區(qū)域。
什么是下界?
相對應(yīng)的,“下界通配符(Lower Bounds Wildcards)”:
Plate<? super Fruit>
表達(dá)的就是相反的概念:一個能放水果以及一切是水果基類的盤子。Plate<? super Fruit>是Plate
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/70773.html
摘要:引用泛型除了方法因不能使用外部實例參數(shù)外,其他繼承實現(xiàn)成員變量,成員方法,方法返回值等都可使用。因此,生成的字節(jié)碼僅包含普通的類,接口和方法。 為什么要使用泛型程序設(shè)計? 一般的類和方法,只能使用具體的類型:要么是基本類型,要么是自定義類的對應(yīng)類型;如果要編寫可以應(yīng)用于多種類型的代碼,這種刻板的限制對代碼的束縛就會很大。----摘自原書Ordinary classes and meth...
摘要:知識點總結(jié)泛型知識點總結(jié)泛型泛型泛型就是參數(shù)化類型適用于多種數(shù)據(jù)類型執(zhí)行相同的代碼泛型中的類型在使用時指定泛型歸根到底就是模版優(yōu)點使用泛型時,在實際使用之前類型就已經(jīng)確定了,不需要強制類型轉(zhuǎn)換。 Java知識點總結(jié)(Java泛型) @(Java知識點總結(jié))[Java, Java泛型] [toc] 泛型 泛型就是參數(shù)化類型 適用于多種數(shù)據(jù)類型執(zhí)行相同的代碼 泛型中的類型在使用時指定 泛...
摘要:靜態(tài)變量是被泛型類的所有實例所共享的。所以引用能完成泛型類型的檢查。對于這個類型系統(tǒng),有如下的一些規(guī)則相同類型參數(shù)的泛型類的關(guān)系取決于泛型類自身的繼承體系結(jié)構(gòu)。事實上,泛型類擴展都不合法。 前言 和C++以模板來實現(xiàn)靜多態(tài)不同,Java基于運行時支持選擇了泛型,兩者的實現(xiàn)原理大相庭徑。C++可以支持基本類型作為模板參數(shù),Java卻只能接受類作為泛型參數(shù);Java可以在泛型類的方法中取得...
摘要:泛型類在類的申明時指定參數(shù),即構(gòu)成了泛型類。換句話說,泛型類可以看成普通類的工廠。的作用就是指明泛型的具體類型,而類型的變量,可以用來創(chuàng)建泛型類的對象。只有聲明了的方法才是泛型方法,泛型類中的使用了泛型的成員方法并不是泛型方法。 什么是泛型? 泛型是JDK 1.5的一項新特性,它的本質(zhì)是參數(shù)化類型(Parameterized Type)的應(yīng)用,也就是說所操作的數(shù)據(jù)類型被指定為一個參數(shù),...
摘要:可以看到,如果我們給泛型類制定了上限,泛型擦除之后就會被替換成類型的上限。相應(yīng)的,泛型類中定義的方法的類型也是如此。參考語言類型擦除下界通配符和的區(qū)別 本篇博客主要介紹了Java類型擦除的定義,詳細(xì)的介紹了類型擦除在Java中所出現(xiàn)的場景。 1. 什么是類型擦除 為了讓你們快速的對類型擦除有一個印象,首先舉一個很簡單也很經(jīng)典的例子。 // 指定泛型為String List list1 ...
閱讀 3610·2021-11-23 09:51
閱讀 1482·2021-11-04 16:08
閱讀 3554·2021-09-02 09:54
閱讀 3620·2019-08-30 15:55
閱讀 2601·2019-08-30 15:54
閱讀 963·2019-08-29 16:30
閱讀 2051·2019-08-29 16:15
閱讀 2322·2019-08-29 14:05