java泛型總結

2021-07-10 06:52:23 字數 4641 閱讀 2602

1.概念

泛型實現了引數化型別的概念,其最初的目的是希望類或方法能夠具備最廣泛的表達能力。通俗來說就是為了避免轉換出錯,限制資料型別。通過解耦類或者方法與所使用的型別之間的約束。

list thelist1 = new arraylist(arrays.aslist(1,2,3,"string"));

for(object o : thelist1)

list thelist2 = new arraylist(arrays.aslist(1,2,3,"string"));

thelist1是原生態型別的list,thelist2是引數化型別(泛型化)的list。thelist1遍歷到「string」的時候會出現classcaseexception異常。thelist2在編譯時就會報錯。

不嚴格的說,前者逃避了編譯時檢查,後者明確告訴編譯器,它應該和能夠持有的物件,在編譯時檢查。

2.泛型的子類化

泛型有子型別化的規則,list是原生態型別list的乙個子型別,而不是引數化型別list的子型別。

考慮如下**:

lista;

listn = a;

n.add(2.5f);

integer num = a.get(0);

假設list是list的子型別,根據父類的引用可以指向子類的物件。讓n指向a,給n新增乙個float型別的元素。接著a.get(0)的型別為float,與最初定義的lista相違背。所以泛型是不可變的,即,對於任意兩個不同的型別type1和type2,list既不是list的子型別,也不是list的超型別。

泛型是通過擦除來實現的。編譯器只為泛型型別生成乙份位元組碼,並將其實例關聯到這份位元組碼上。型別擦除的關鍵在於從泛型型別中清除型別引數的相關資訊,並且再必要的時候新增型別檢查和型別轉換的方法。

當原始型別一致,型別引數不一致時,其為同乙個物件。

如下**:

listtype1 = new arraylist();

listtype2 = new arraylist();

system.out.println(type1.getclass() == type2.getclass());

結果為true。

建立泛型陣列是非法的,即new list()、newlist和new e都是不允許的。因為它們違背了泛型系統提供的基本保證——型別安全。

有一種特殊情況,當乙個方法接受泛型的可變型別。這時會出現警告,這是由於 每次呼叫可變引數方法時,就會建立乙個陣列來存放可變引數。如果這個陣列的元素型別不是可具體會的(比如泛型),就會得到一條警告。除了用supresswarnings(「unchecked」)消除這些警告,別無他法。

public void themethod(@suppresswarnings("unchecked") list...a)

3.優先考慮泛型

考慮如下**:

public class stack

public void push(e e)

public e pop()

return null; }

private boolean isempty()

private void ensurecapacity()

}}

會出現一條錯誤。不能建立不可具體化的型別的資料,如e,是什麼型別,不知道。解決這個問題有兩種方法。

第一種:建立乙個object的陣列,並將它轉換成泛型陣列型別。

public stack()

但會出現一條警告,說明型別是不安全的。你必須確保未受檢的轉換不會危及到程式的型別安全性。elements儲存在乙個私有的域中,永遠不會被返回到客戶端,或者傳給任何其他方法。這個陣列中儲存的唯一元素,是傳給push方法的那些元素,而push方法只能接受e型別的引數,從而保證了未受檢的轉換不會有任何危害。

第二種:將elements域的型別從e改為object。

private object elements;
public e pop()

return null;

}

有乙個錯誤,需要強制型別轉化為e,由push方法能保證elements裡的元素型別為e,所以強制轉換為e時不會出現classcaseexception。

4.型別萬用字元

考慮如下**:

class box

public box(integer data)

public integer getdata()

public void setdata(integer data)

}

我們可以很容易得到型別引數為integer的box物件,如果型別引數為string、number呢,是不是重新定義box類呢。只要使用型別萬用字元就可重用之前寫好的**。將integer改為e。如下**。

class box

public box(e data)

public e getdata()

public void setdata(e data)

}

當我們需要什麼型別時,定義實參為所需型別即可。

5.有限萬用字元

<? extends e>表示e繼承某種型別的一種型別

看如下**:

stacknumberstack = new stack();

iterableintegers = null;

numberstack.pushall(integers);

會報錯,因為pushall的輸入引數型別不應該為「e的iterable介面」,而應該為「e繼承的iterable介面」。所以應該把pushall的方法引數改為

public void pushall(iterable<? extends e> src)

<?super e>表示某種e的超型別

看**:

stacknumberstack = new stack();

collectionobjects = null;

numberstack.popall(objects);

原因分析:collection不是collection的子型別。popall的輸入引數型別不應該為「e的集合」,而應該為「某種以e為超類的集合」。

修改popall方法

public void popall(collection<? super e> dst)

}

上面的objects裡存放的是object型別,當傳入到popall時,dst接受的實參型別為collection<? super object>,即以object為超類的集合。所以,dst當然可以add()number型別的資料啦。

說明:

public static void test(list<?> list)

set報錯的原因是因為此時方法中的型別是不可具體化的(reified),你可以傳遞乙個string,number,book,等任何繼承自object的類作為list的引數型別給test方法,而list要求集合中的型別必須是一致的,set的時候沒有辦法保證set進去的資料型別是否和list中原本的型別一致,比如你傳給test方法的是list, 那麼在方法中set進去乙個object顯然型別就不一致了。這也是萬用字元帶來靈活性的同時所要付出的代價。

結論:使用了<? extends e> 這樣的萬用字元,test方法的引數list變成了只能get不能set(除了null) 或者不嚴謹的說它變成了唯讀引數了, 有些類似乙個生產者,提供資料。

public static void test(list<? super number> list)

這時get只能get出最寬泛的父型別,即object。

這時set的時候,必須是number或number的子類。

原因和上面的get類似。

結論: 使用了<?super e> 這種萬用字元,test方法的引數list的get受到了很大的制約,只能最寬泛的方式來獲取list中的資料,相當於get只提供了資料最小級別的訪問許可權(想想,你可能原本是放進去了乙個book,卻只能當作object來訪問)。它更多適合於set的使用場景,像是乙個消費者,主要用來消費資料。

pecs表示producer-extends,consumer-super。來總結什麼時候用<?  extends t>和<? super t>。

在上訴的stack示例中,pushall的src引數產生e例項供stack使用,因此src相應的型別為iterable<? extends e>;popall的dst引數通過stack消費e例項,因此dst相應的型別為collection<? super e>。

如果你想從乙個資料型別裡獲取資料,使用<? extends t>

如果你想把物件寫入乙個資料結構裡,使用< ? super t>

如果你既想存,又想取,那就別用萬用字元。

Java 泛型總結

泛型指引數化型別的能力,可以定義帶泛型型別的類或方法,隨後編譯器會用具體的型別來替換它。在泛型產生之前,像集合的訪問都是靠強制型別轉換 public class arraylist public void add object o string filename string names.get 0...

Java泛型總結

1 泛型主要是用來年解決資料型別安全的問題,用標識來代替屬性的型別或者返回值的型別 2 在使用泛型的時候可以有以下幾種形式 泛型介面 泛型類 萬用字元做泛型引數 泛型方法 泛型陣列 3 以下通過 說明 package com.sun.demo 一 定義泛型介面 inte ce father 二 定義...

java泛型總結

提高 的復用性 1.泛型類 package xinceshi class box public t get public class iotest 2.泛型函式class util 呼叫的時候和呼叫普通函式一樣,不用加尖括號 3.邊界符public static int greaterthan t ...