java學習筆記(Core Java) 8 泛型

來源:互聯網
上載者:User

標籤:die   man   泛型   var   構造   set   比較   類型擦除   list   

泛型
一.定義一個泛型類
public class Pair<T>
{
private T _first;

public Pair(T first) {this._first = first;}

public T getfirst() {return _first;}
}
java中類型變數使用大寫字母且比較短
E:元素類型 K,V 表的關鍵字與值的類型 T(U/S)任意類型

泛型方法:要麼傳回型別是泛型,要麼參數是泛型
public static <T> getMiddle(T... a)
{
return a[a.length/2];
}
調用時,程式會自動識別泛型型別。偶爾會有錯誤

C++:與C++模板類(template)類似,但有著本質區別

二.限定一個類型變數,為類型變數提供一個父類介面,方便該類型擁有某些方法(使用extends而不是implements)
public static <T extends Compareable> T getMiddle(T ...);

可以綁定多個限定類,使用&隔開
T extends Compareable & Serializable

三.泛型代碼與虛擬機器
所有的泛型代碼,都會提供一個原始類型。就是刪除型別參數後面的泛型型別名字,替換為限定類。沒有限定類的用object代替。有多個限定類的,將使用第一個限定類代替T,並繼承第二個限定類
public class Pair
{
private object _first;

public Pair(object first) {this._first = first;}

public object getFirst() {return _first;}
}

C++:c++的每個模板執行個體化產生不同的類型,這一現象成為“模板代碼膨脹”

四.類型擦出與多態調用、橋方法
翻譯泛型運算式:如果擦除傳回型別,則預設返回object類型,編譯器將強制插入類型轉換
翻譯泛型方法: 泛型類父類類型擦出後,對於子類來說,重寫父類的方法可能會存在破壞多態性的情況
完整的方法: public static DataInterval extends Pair<Data>
擦除類型後: public static DataInterval extends Pair //該類中所有關於T的域或方法,都會被Object代替
如果子類重寫父類的某個方法:例如: setSecond,則父類參數列表為object,而子類的參數列表仍為子類定義的Data類型,這與重寫的特徵相違背。破壞了多態。到底是調用哪一個方法呢?
父類:setSecond(Object value);//setSecond(T value);
子類:setSecond(Data value);
setSecond(Object value);//繼承的父類

//調用
DataInterval interval = new DataInterval(...);
Pair<Data> pair = interval;
pair.setSecond(aData);
由於pair引用了DataInterval對象,所以我們應該要用DataInterval.setSecond。但問題在於類型擦除與多態發生了衝突。不知道要用的是哪一個

JVM工作原理如下:
1.變數pair聲明為Pair<Date>,該類型只有一個setSecond(Object)方法,虛擬機器用pair引用的對象去調用這個setSecond(Object)方法。
2.pair引用的對象是DateInterval,所以將會調用DateInterval.setSecond(Object)方法,這個方法是橋方法。
3.這個橋方法會調用DateInterval.setSecond(Date)方法。

解決方案:需要在編譯器內產生一個橋方法
public void setSecond(Object value)
{
setSecond(Data)value); //強制類型轉換!無論怎麼調用,都會調用setSecond(Data value)方法
}

如果覆蓋了子類的getSecond方法;並且使用橋方法
class DateInterval extends Pair<Date> {
    public Date getSecond() {
        return (Date) super.getSecond().clone();
    }
}
擦除類型後編程:
Data getSecond();
Object getSecond();//同樣也是兩個方法
實際上,jvm可以通過傳回型別來區分要調用哪個方法

橋方法不僅用於泛型型別; 還有, 在一個方法覆蓋另一個方法時可以指定一個更嚴格的傳回型別,指明要調用的方法:
public Employee clone() throws ClooneNotSupportedException {。。。}
實際上,Employee類有兩個clone方法,object clone()以及Employee clone;合成橋方法調用了新定義的方法

java泛型轉換的事實:
1.虛擬機器中沒有泛型,只有普通的類和方法
2.所有的型別參數都會使用限定類型轉換
3.橋方法被合成保持多態
4.為保持型別安全,必要時插入強制類型轉換

五.泛型的局限性
1.不能使用及類型執行個體化型別參數 例如:沒有Pair<double>,只有Pair<Double>,可以使用封裝器封裝基本類型
2.運行時類型查詢只適用於原始類型
虛擬機器中的對象總有一個特定的非泛型型別,所有的類型查詢只產生原始類型。(instanceof,getCLass方法等.凡是涉及到使用instanceof還是強制類型轉換,都會產生一個警告)
pair<String> strobg = "..."; ==>Pair
pair<Employee> Empobg = "..."; ==> Pair
if(stringobg.getClass() == Empobg.getClass()) //they is equal
3.不能建立參數化的數組
Pair<String>[] table = new Pair<String>[10]
擦出後Pair[] table可以轉變為 object[]數組,如果試圖存入其他類型的變數,就會拋出異常
如果要收集參數化型別對象,只有一種安全有效方法,使用AllayList
AllayList<Pair<String>>
4.Varargs警告:如果參數列表數量可變,那麼就會產生類似上述的情況出項,參數列表數目可變其實也就是將參數列表裡的所有相同類型的參數封裝到數組裡去。這時會產生一個警告,可以使用@SuppressWarnings("unchecked")標註(javaSE 7還可以使用@SaveVarargs標註該方法)
@Savavarargs
public static<T> void addAll(Collect<T> coll, T... ts);
5.不能執行個體化類型變數,不能構造一個泛型數組
不能 new T(...),new T[]或者T.class,因為類型擦出後,T將變成object類型
或者object[2],new object()不是我們希望看到的,可以使用反射去建立對象
//first.T.class是不合法的
public static <T> Pair<T> makePair(Class<T> cl) //<T> 表明泛型方法
{
try{
return new Pair<>(cl.newInstance(),cl.newInstance())
}
catch(Exception ex)
{
return null
}
}
Pair<String> p = Pair.makePair(String.class);

6.泛型類的靜態上下文中類型變數無效
不能在靜態域或方法中參考型別變數
public class SingLeton<T>
{
private static T singleInstance; //Error

public static T getSingleInstance //Error
{
if(singleleInstance == null)
return singleInstance;
}
}

7.不能拋出或捕捉泛型類的執行個體
基於泛型類拓展的Throwable都是不合法的
8.注意類型擦出後的衝突

五.泛型繼承
無論S,T之間有什麼關係。Pair<S>和Pair<T>之間沒有任何關係,不能隨意調用類中的方法,解決見《六,萬用字元》
永遠可以吧泛型型別轉換為原始類型,這一點可以處理遺留代碼。但是仍不保證一點安全

六.萬用字元類型
Pair<? extends Employee>
表示任何泛型Pair類型,它的型別參數是Employee的子類,如Pair<Manager>,但不是Pair<String>等其他類型

public static void paintBuddies(<Pair<? extends Employee> p)

類型<Pair<Manager>是<Pair<? extends Employee>的 子集

1.萬用字元超類型限定
2.無限頂萬用字元
3.萬用字元捕獲

六、反射與泛型
Class類是泛型,例如String.class實際上是一個Class<String>類的對象(事實上,是唯一的對象)
型別參數使得Class<T>方法的傳回值更具有針對性。
T newInstance()
T cast(object obj)
T[] getEnumConstances()
...
//原書 554頁

java學習筆記(Core Java) 8 泛型

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.