java高端代碼泛型 java泛型高級使用

java中什么是泛型,怎么用泛型?

這是在各種Java泛型面試中,一開場你就會被問到的問題中的一個,主要集中在初級和中級面試中:

創(chuàng)新互聯(lián)公司堅持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:成都做網(wǎng)站、網(wǎng)站制作、企業(yè)官網(wǎng)、英文網(wǎng)站、手機端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時代的富陽網(wǎng)站設(shè)計、移動媒體設(shè)計的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!

1:什么是泛型?

泛型就是廣泛的類型,也是一種數(shù)據(jù)類型,而這種數(shù)據(jù)類型可以是任意類型,編寫過程中當(dāng)中不能確定類型,創(chuàng)建對象時必須指定具體類型,不指定也可以,但是會出現(xiàn)一些錯誤。

泛型是編譯器行為,只能在編譯期有效,如果能夠跨過編譯器,那么泛型就沒有任何意義了。

2、泛型類

怎么定義泛型類?

在類后面加,中可以編寫任意長度任意字符,不能是數(shù)值。(一般用26個大寫英文字母表示)

泛型類 具體類型 變量名 = new 泛型類();

3.怎么使用泛型

有以下幾種使用場景以及放在那種位置

泛型只能定義引用數(shù)據(jù)類型,而不能使用基本數(shù)據(jù)類型

泛型類、泛型方法、泛型接口、泛型通配符

例如:作用在類上時( public class Animal E { E pet; } ) , 泛型跟在類后邊,可以指定用了泛型的類內(nèi)部的 pet 的類型。

作用在對象上時( AnimalDog str = new AnimalDog(); ) , 泛型跟在類后邊 , 使得對象類的的 pet 屬性為 Dog類型。

java中什么叫泛型??

有泛型參數(shù),泛型方法,這篇文件寫的很好,你仔細 讀一下,可以多讀幾次,總會有收獲滴

java泛型

java泛型

什么是泛型?

泛型(Generic type 或者 generics)是對 Java 語言的類型系統(tǒng)的一種擴展,以支持創(chuàng)建可以按類型進行參數(shù)化的類??梢园杨愋蛥?shù)看作是使用參數(shù)化類型時指定的類型的一個占位符,就像方法的形式參數(shù)是運行時傳遞的值的占位符一樣。

可以在集合框架(Collection framework)中看到泛型的動機。例如,Map 類允許您向一個 Map 添加任意類的對象,即使最常見的情況是在給定映射(map)中保存某個特定類型(比如 String)的對象。

因為 Map.get() 被定義為返回 Object,所以一般必須將 Map.get() 的結(jié)果強制類型轉(zhuǎn)換為期望的類型,如下面的代碼所示:

Map m = new HashMap();

m.put("key", "blarg");

String s = (String) m.get("key");

要讓程序通過編譯,必須將 get() 的結(jié)果強制類型轉(zhuǎn)換為 String,并且希望結(jié)果真的是一個 String。但是有可能某人已經(jīng)在該映射中保存了不是 String 的東西,這樣的話,上面的代碼將會拋出 ClassCastException。

理想情況下,您可能會得出這樣一個觀點,即 m 是一個 Map,它將 String 鍵映射到 String 值。這可以讓您消除代碼中的強制類型轉(zhuǎn)換,同時獲得一個附加的類型檢查層,該檢查層可以防止有人將錯誤類型的鍵或值保存在集合中。這就是泛型所做的工作。

泛型的好處

Java 語言中引入泛型是一個較大的功能增強。不僅語言、類型系統(tǒng)和編譯器有了較大的變化,以支持泛型,而且類庫也進行了大翻修,所以許多重要的類,比如集合框架,都已經(jīng)成為泛型化的了。這帶來了很多好處:

類型安全。 泛型的主要目標(biāo)是提高 Java 程序的類型安全。通過知道使用泛型定義的變量的類型限制,編譯器可以在一個高得多的程度上驗證類型假設(shè)。沒有泛型,這些假設(shè)就只存在于程序員的頭腦中(或者如果幸運的話,還存在于代碼注釋中)。

Java 程序中的一種流行技術(shù)是定義這樣的集合,即它的元素或鍵是公共類型的,比如“String 列表”或者“String 到 String 的映射”。通過在變量聲明中捕獲這一附加的類型信息,泛型允許編譯器實施這些附加的類型約束。類型錯誤現(xiàn)在就可以在編譯時被捕獲了,而不是在運行時當(dāng)作 ClassCastException 展示出來。將類型檢查從運行時挪到編譯時有助于您更容易找到錯誤,并可提高程序的可靠性。

消除強制類型轉(zhuǎn)換。 泛型的一個附帶好處是,消除源代碼中的許多強制類型轉(zhuǎn)換。這使得代碼更加可讀,并且減少了出錯機會。

盡管減少強制類型轉(zhuǎn)換可以降低使用泛型類的代碼的羅嗦程度,但是聲明泛型變量會帶來相應(yīng)的羅嗦。比較下面兩個代碼例子。

該代碼不使用泛型:

List li = new ArrayList();

li.put(new Integer(3));

Integer i = (Integer) li.get(0);

該代碼使用泛型:

ListInteger li = new ArrayListInteger();

li.put(new Integer(3));

Integer i = li.get(0);

在簡單的程序中使用一次泛型變量不會降低羅嗦程度。但是對于多次使用泛型變量的大型程序來說,則可以累積起來降低羅嗦程度。

潛在的性能收益。 泛型為較大的優(yōu)化帶來可能。在泛型的初始實現(xiàn)中,編譯器將強制類型轉(zhuǎn)換(沒有泛型的話,程序員會指定這些強制類型轉(zhuǎn)換)插入生成的字節(jié)碼中。但是更多類型信息可用于編譯器這一事實,為未來版本的 JVM 的優(yōu)化帶來可能。

由于泛型的實現(xiàn)方式,支持泛型(幾乎)不需要 JVM 或類文件更改。所有工作都在編譯器中完成,編譯器生成類似于沒有泛型(和強制類型轉(zhuǎn)換)時所寫的代碼,只是更能確保類型安全而已。

泛型用法的例子

泛型的許多最佳例子都來自集合框架,因為泛型讓您在保存在集合中的元素上指定類型約束??紤]這個使用 Map 類的例子,其中涉及一定程度的優(yōu)化,即 Map.get() 返回的結(jié)果將確實是一個 String:

Map m = new HashMap();

m.put("key", "blarg");

String s = (String) m.get("key");

如果有人已經(jīng)在映射中放置了不是 String 的其他東西,上面的代碼將會拋出 ClassCastException。泛型允許您表達這樣的類型約束,即 m 是一個將 String 鍵映射到 String 值的 Map。這可以消除代碼中的強制類型轉(zhuǎn)換,同時獲得一個附加的類型檢查層,這個檢查層可以防止有人將錯誤類型的鍵或值保存在集合中。

下面的代碼示例展示了 JDK 5.0 中集合框架中的 Map 接口的定義的一部分:

public interface MapK, V {

public void put(K key, V value);

public V get(K key);

}

注意該接口的兩個附加物:

類型參數(shù) K 和 V 在類級別的規(guī)格說明,表示在聲明一個 Map 類型的變量時指定的類型的占位符。

在 get()、put() 和其他方法的方法簽名中使用的 K 和 V。

為了贏得使用泛型的好處,必須在定義或?qū)嵗?Map 類型的變量時為 K 和 V 提供具體的值。以一種相對直觀的方式做這件事:

MapString, String m = new HashMapString, String();

m.put("key", "blarg");

String s = m.get("key");

當(dāng)使用 Map 的泛型化版本時,您不再需要將 Map.get() 的結(jié)果強制類型轉(zhuǎn)換為 String,因為編譯器知道 get() 將返回一個 String。

在使用泛型的版本中并沒有減少鍵盤錄入;實際上,比使用強制類型轉(zhuǎn)換的版本需要做更多鍵入。使用泛型只是帶來了附加的類型安全。因為編譯器知道關(guān)于您將放進 Map 中的鍵和值的類型的更多信息,所以類型檢查從執(zhí)行時挪到了編譯時,這會提高可靠性并加快開發(fā)速度。

向后兼容

在 Java 語言中引入泛型的一個重要目標(biāo)就是維護向后兼容。盡管 JDK 5.0 的標(biāo)準(zhǔn)類庫中的許多類,比如集合框架,都已經(jīng)泛型化了,但是使用集合類(比如 HashMap 和 ArrayList)的現(xiàn)有代碼將繼續(xù)不加修改地在 JDK 5.0 中工作。當(dāng)然,沒有利用泛型的現(xiàn)有代碼將不會贏得泛型的類型安全好處。

二 泛型基礎(chǔ)

類型參數(shù)

在定義泛型類或聲明泛型類的變量時,使用尖括號來指定形式類型參數(shù)。形式類型參數(shù)與實際類型參數(shù)之間的關(guān)系類似于形式方法參數(shù)與實際方法參數(shù)之間的關(guān)系,只是類型參數(shù)表示類型,而不是表示值。

泛型類中的類型參數(shù)幾乎可以用于任何可以使用類名的地方。例如,下面是 java.util.Map 接口的定義的摘錄:

public interface MapK, V {

public void put(K key, V value);

public V get(K key);

}

Map 接口是由兩個類型參數(shù)化的,這兩個類型是鍵類型 K 和值類型 V。(不使用泛型)將會接受或返回 Object 的方法現(xiàn)在在它們的方法簽名中使用 K 或 V,指示附加的類型約束位于 Map 的規(guī)格說明之下。

當(dāng)聲明或者實例化一個泛型的對象時,必須指定類型參數(shù)的值:

MapString, String map = new HashMapString, String();

注意,在本例中,必須指定兩次類型參數(shù)。一次是在聲明變量 map 的類型時,另一次是在選擇 HashMap 類的參數(shù)化以便可以實例化正確類型的一個實例時。

編譯器在遇到一個 MapString, String 類型的變量時,知道 K 和 V 現(xiàn)在被綁定為 String,因此它知道在這樣的變量上調(diào)用 Map.get() 將會得到 String 類型。

除了異常類型、枚舉或匿名內(nèi)部類以外,任何類都可以具有類型參數(shù)。

命名類型參數(shù)

推薦的命名約定是使用大寫的單個字母名稱作為類型參數(shù)。這與 C++ 約定有所不同(參閱 附錄 A:與 C++ 模板的比較),并反映了大多數(shù)泛型類將具有少量類型參數(shù)的假定。對于常見的泛型模式,推薦的名稱是:

K —— 鍵,比如映射的鍵。

V —— 值,比如 List 和 Set 的內(nèi)容,或者 Map 中的值。

E —— 異常類。

T —— 泛型。

泛型不是協(xié)變的

關(guān)于泛型的混淆,一個常見的來源就是假設(shè)它們像數(shù)組一樣是協(xié)變的。其實它們不是協(xié)變的。ListObject 不是 ListString 的父類型。

如果 A 擴展 B,那么 A 的數(shù)組也是 B 的數(shù)組,并且完全可以在需要 B[] 的地方使用 A[]:

Integer[] intArray = new Integer[10];

Number[] numberArray = intArray;

上面的代碼是有效的,因為一個 Integer 是 一個 Number,因而一個 Integer 數(shù)組是 一個 Number 數(shù)組。但是對于泛型來說則不然。下面的代碼是無效的:

ListInteger intList = new ArrayListInteger();

ListNumber numberList = intList; // invalid

最初,大多數(shù) Java 程序員覺得這缺少協(xié)變很煩人,或者甚至是“壞的(broken)”,但是之所以這樣有一個很好的原因。如果可以將 ListInteger 賦給 ListNumber,下面的代碼就會違背泛型應(yīng)該提供的類型安全:

ListInteger intList = new ArrayListInteger();

ListNumber numberList = intList; // invalid

numberList.add(new Float(3.1415));

因為 intList 和 numberList 都是有別名的,如果允許的話,上面的代碼就會讓您將不是 Integers 的東西放進 intList 中。但是,正如下一屏將會看到的,您有一個更加靈活的方式來定義泛型。

類型通配符

假設(shè)您具有該方法:

void printList(List l) {

for (Object o : l)

System.out.println(o);

}

上面的代碼在 JDK 5.0 上編譯通過,但是如果試圖用 ListInteger 調(diào)用它,則會得到警告。出現(xiàn)警告是因為,您將泛型(ListInteger)傳遞給一個只承諾將它當(dāng)作 List(所謂的原始類型)的方法,這將破壞使用泛型的類型安全。

如果試圖編寫像下面這樣的方法,那么將會怎么樣?

void printList(ListObject l) {

for (Object o : l)

System.out.println(o);

}

它仍然不會通過編譯,因為一個 ListInteger 不是 一個 ListObject(正如前一屏 泛型不是協(xié)變的 中所學(xué)的)。這才真正煩人 —— 現(xiàn)在您的泛型版本還沒有普通的非泛型版本有用!

解決方案是使用類型通配符:

void printList(List? l) {

for (Object o : l)

System.out.println(o);

}

上面代碼中的問號是一個類型通配符。它讀作“問號”。List? 是任何泛型 List 的父類型,所以您完全可以將 ListObject、ListInteger 或 ListListListFlutzpah 傳遞給 printList()。

類型通配符的作用

前一屏 類型通配符 中引入了類型通配符,這讓您可以聲明 List? 類型的變量。您可以對這樣的 List 做什么呢?非常方便,可以從中檢索元素,但是不能添加元素。原因不是編譯器知道哪些方法修改列表哪些方法不修改列表,而是(大多數(shù))變化的方法比不變化的方法需要更多的類型信息。下面的代碼則工作得很好:

ListInteger li = new ArrayListInteger();

li.add(new Integer(42));

List? lu = li;

System.out.println(lu.get(0));

為什么該代碼能工作呢?對于 lu,編譯器一點都不知道 List 的類型參數(shù)的值。但是編譯器比較聰明,它可以做一些類型推理。在本例中,它推斷未知的類型參數(shù)必須擴展 Object。(這個特定的推理沒有太大的跳躍,但是編譯器可以作出一些非常令人佩服的類型推理,后面就會看到(在 底層細節(jié) 一節(jié)中)。所以它讓您調(diào)用 List.get() 并推斷返回類型為 Object。

另一方面,下面的代碼不能工作:

ListInteger li = new ArrayListInteger();

li.add(new Integer(42));

List? lu = li;

lu.add(new Integer(43)); // error

在本例中,對于 lu,編譯器不能對 List 的類型參數(shù)作出足夠嚴密的推理,以確定將 Integer 傳遞給 List.add() 是類型安全的。所以編譯器將不允許您這么做。

以免您仍然認為編譯器知道哪些方法更改列表的內(nèi)容哪些不更改列表內(nèi)容,請注意下面的代碼將能工作,因為它不依賴于編譯器必須知道關(guān)于 lu 的類型參數(shù)的任何信息:

ListInteger li = new ArrayListInteger();

li.add(new Integer(42));

List? lu = li;

lu.clear();

泛型方法

(在 類型參數(shù) 一節(jié)中)您已經(jīng)看到,通過在類的定義中添加一個形式類型參數(shù)列表,可以將類泛型化。方法也可以被泛型化,不管它們定義在其中的類是不是泛型化的。

泛型類在多個方法簽名間實施類型約束。在 ListV 中,類型參數(shù) V 出現(xiàn)在 get()、add()、contains() 等方法的簽名中。當(dāng)創(chuàng)建一個 MapK, V 類型的變量時,您就在方法之間宣稱一個類型約束。您傳遞給 add() 的值將與 get() 返回的值的類型相同。

類似地,之所以聲明泛型方法,一般是因為您想要在該方法的多個參數(shù)之間宣稱一個類型約束。例如,下面代碼中的 ifThenElse() 方法,根據(jù)它的第一個參數(shù)的布爾值,它將返回第二個或第三個參數(shù):

public T T ifThenElse(boolean b, T first, T second) {

return b ? first : second;

}

注意,您可以調(diào)用 ifThenElse(),而不用顯式地告訴編譯器,您想要 T 的什么值。編譯器不必顯式地被告知 T 將具有什么值;它只知道這些值都必須相同。編譯器允許您調(diào)用下面的代碼,因為編譯器可以使用類型推理來推斷出,替代 T 的 String 滿足所有的類型約束:

String s = ifThenElse(b, "a", "b");

類似地,您可以調(diào)用:

Integer i = ifThenElse(b, new Integer(1), new Integer(2));

但是,編譯器不允許下面的代碼,因為沒有類型會滿足所需的類型約束:

String s = ifThenElse(b, "pi", new Float(3.14));

為什么您選擇使用泛型方法,而不是將類型 T 添加到類定義呢?(至少)有兩種情況應(yīng)該這樣做:

當(dāng)泛型方法是靜態(tài)的時,這種情況下不能使用類類型參數(shù)。

當(dāng) T 上的類型約束對于方法真正是局部的時,這意味著沒有在相同類的另一個 方法簽名中使用相同 類型 T 的約束。通過使得泛型方法的類型參數(shù)對于方法是局部的,可以簡化封閉類型的簽名。

有限制類型

在前一屏 泛型方法 的例子中,類型參數(shù) V 是無約束的或無限制的 類型。有時在還沒有完全指定類型參數(shù)時,需要對類型參數(shù)指定附加的約束。

考慮例子 Matrix 類,它使用類型參數(shù) V,該參數(shù)由 Number 類來限制:

public class MatrixV extends Number { ... }

編譯器允許您創(chuàng)建 MatrixInteger 或 MatrixFloat 類型的變量,但是如果您試圖定義 MatrixString 類型的變量,則會出現(xiàn)錯誤。類型參數(shù) V 被判斷為由 Number 限制 。在沒有類型限制時,假設(shè)類型參數(shù)由 Object 限制。這就是為什么前一屏 泛型方法 中的例子,允許 List.get() 在 List? 上調(diào)用時返回 Object,即使編譯器不知道類型參數(shù) V 的類型。

三 一個簡單的泛型類

編寫基本的容器類

此時,您可以開始編寫簡單的泛型類了。到目前為止,泛型類最常見的用例是容器類(比如集合框架)或者值持有者類(比如 WeakReference 或 ThreadLocal)。我們來編寫一個類,它類似于 List,充當(dāng)一個容器。其中,我們使用泛型來表示這樣一個約束,即 Lhist 的所有元素將具有相同類型。為了實現(xiàn)起來簡單,Lhist 使用一個固定大小的數(shù)組來保存值,并且不接受 null 值。

Lhist 類將具有一個類型參數(shù) V(該參數(shù)是 Lhist 中的值的類型),并將具有以下方法:

public class LhistV {

public Lhist(int capacity) { ... }

public int size() { ... }

public void add(V value) { ... }

public void remove(V value) { ... }

public V get(int index) { ... }

}

要實例化 Lhist,只要在聲明時指定類型參數(shù)和想要的容量:

LhistString stringList = new LhistString(10);

實現(xiàn)構(gòu)造函數(shù)

在實現(xiàn) Lhist 類時,您將會遇到的第一個攔路石是實現(xiàn)構(gòu)造函數(shù)。您可能會像下面這樣實現(xiàn)它:

public class LhistV {

private V[] array;

public Lhist(int capacity) {

array = new V[capacity]; // illegal

}

}

這似乎是分配后備數(shù)組最自然的一種方式,但是不幸的是,您不能這樣做。具體原因很復(fù)雜,當(dāng)學(xué)習(xí)到 底層細節(jié) 一節(jié)中的“擦除”主題時,您就會明白。分配后備數(shù)組的實現(xiàn)方式很古怪且違反直覺。下面是構(gòu)造函數(shù)的一種可能的實現(xiàn)(該實現(xiàn)使用集合類所采用的方法):

public class LhistV {

private V[] array;

public Lhist(int capacity) {

array = (V[]) new Object[capacity];

}

}

另外,也可以使用反射來實例化數(shù)組。但是這樣做需要給構(gòu)造函數(shù)傳遞一個附加的參數(shù) —— 一個類常量,比如 Foo.class。后面在 ClassT 一節(jié)中將討論類常量。

實現(xiàn)方法

實現(xiàn) Lhist 的方法要容易得多。下面是 Lhist 類的完整實現(xiàn):

public class LhistV {

private V[] array;

private int size;

public Lhist(int capacity) {

array = (V[]) new Object[capacity];

}

public void add(V value) {

if (size == array.length)

throw new IndexOutOfBoundsException(Integer.toString(size));

else if (value == null)

throw new NullPointerException();

array[size++] = value;

}

public void remove(V value) {

int removalCount = 0;

for (int i=0; isize; i++) {

if (array[i].equals(value))

++removalCount;

else if (removalCount 0) {

array[i-removalCount] = array[i];

array[i] = null;

}

}

size -= removalCount;

}

public int size() { return size; }

public V get(int i) {

if (i = size)

throw new IndexOutOfBoundsException(Integer.toString(i));

return array[i];

}

}

注意,您在將會接受或返回 V 的方法中使用了形式類型參數(shù) V,但是您一點也不知道 V 具有什么樣的方法或域,因為這些對泛型代碼是不可知的。

使用 Lhist 類

使用 Lhist 類很容易。要定義一個整數(shù) Lhist,只需要在聲明和構(gòu)造函數(shù)中為類型參數(shù)提供一個實際值即可:

LhistInteger li = new LhistInteger(30);

編譯器知道,li.get() 返回的任何值都將是 Integer 類型,并且它還強制傳遞給 li.add() 或 li.remove() 的任何東西都是 Integer。除了實現(xiàn)構(gòu)造函數(shù)的方式很古怪之外,您不需要做任何十分特殊的事情以使 Lhist 是一個泛型類。

java中的泛型怎么理解?舉例說明下

給你一個原來我看過的別人的解釋吧:

泛型是Java SE 1.5的新特性,泛型的本質(zhì)是參數(shù)化類型,也就是說所操作的數(shù)據(jù)類型被指定為一個參數(shù)。這種參數(shù)類型可以用在類、接口和方法的創(chuàng)建中,分別稱為泛型類、泛型接口、泛型方法。 Java語言引入泛型的好處是安全簡單。 在Java SE 1.5之前,沒有泛型的情況的下,通過對類型Object的引用來實現(xiàn)參數(shù)的“任意化”,“任意化”帶來的缺點是要做顯式的強制類型轉(zhuǎn)換,而這種轉(zhuǎn)換是要求開發(fā)者對實際參數(shù)類型可以預(yù)知的情況下進行的。對于強制類型轉(zhuǎn)換錯誤的情況,編譯器可能不提示錯誤,在運行的時候才出現(xiàn)異常,這是一個安全隱患。 泛型的好處是在編譯的時候檢查類型安全,并且所有的強制轉(zhuǎn)換都是自動和隱式的,提高代碼的重用率。 泛型在使用中還有一些規(guī)則和限制: 1、泛型的類型參數(shù)只能是類類型(包括自定義類),不能是簡單類型。 2、同一種泛型可以對應(yīng)多個版本(因為參數(shù)類型是不確定的),不同版本的泛型類實例是不兼容的。 3、泛型的類型參數(shù)可以有多個。 4、泛型的參數(shù)類型可以使用extends語句,例如t extends="" superclass=""。習(xí)慣上成為“有界類型”。 5、泛型的參數(shù)類型還可以是通配符類型。例如Class classType = Class.forName(java.lang.String); 泛型還有接口、方法等等,內(nèi)容很多,需要花費一番功夫才能理解掌握并熟練應(yīng)用。在此給出我曾經(jīng)了解泛型時候?qū)懗龅膬蓚€例子(根據(jù)看的印象寫的),實現(xiàn)同樣的功能,一個使用了泛型,一個沒有使用,通過對比,可以很快學(xué)會泛型的應(yīng)用,學(xué)會這個基本上學(xué)會了泛型70%的內(nèi)容。 例子一:使用了泛型 public class Gent { private T ob; //定義泛型成員變量 public Gen(T ob) { this.ob = ob; } public T getOb() { return ob; } public void setOb(T ob) { this.ob = ob; } public void showTyep() { System.out.println("T的實際類型是: " + ob.getClass().getName()); } } public class GenDemo { public static void main(String[] args){ //定義泛型類Gen的一個Integer版本 Geninteger intOb=new Geninteger(88); intOb.showTyep(); int i= intOb.getOb(); System.out.println("value= " + i); System.out.println("----------------------------------"); //定義泛型類Gen的一個String版本 Genstring strOb=new Genstring("Hello Gen!"); strOb.showTyep(); String s=strOb.getOb(); System.out.println("value= " + s); } } 例子二:沒有使用泛型 public class Gen2 { private Object ob; //定義一個通用類型成員 public Gen2(Object ob) { this.ob = ob; } public Object getOb() { return ob; } public void setOb(Object ob) { this.ob = ob; } public void showTyep() { System.out.println("T的實際類型是: " + ob.getClass().getName()); } } public class GenDemo2 { public static void main(String[] args) { //定義類Gen2的一個Integer版本 Gen2 intOb = new Gen2(new Integer(88)); intOb.showTyep(); int i = (Integer) intOb.getOb(); System.out.println("value= " + i); System.out.println("----------------------------------"); //定義類Gen2的一個String版本 Gen2 strOb = new Gen2("Hello Gen!"); strOb.showTyep(); String s = (String) strOb.getOb(); System.out.println("value= " + s); } } 運行結(jié)果: 兩個例子運行Demo結(jié)果是相同的,控制臺輸出結(jié)果如下: T的實際類型是: java.lang.Integer value= 88 ---------------------------------- T的實際類型是: java.lang.String value= Hello Gen! Process finished with exit code 0

java中的泛型 求詳細解釋

1、Java泛型

其實Java的泛型就是創(chuàng)建一個用類型作為參數(shù)的類。就象我們寫類的方法一樣,方法是這樣的method(String str1,String str2 ),方法中參數(shù)str1、str2的值是可變的。而泛型也是一樣的,這樣寫class Java_Generics<K,V>,這里邊的K和V就象方法中的參數(shù)str1和str2,也是可變。下面看看例子:

//code list 1

import Java.util.Hashtable;

class TestGen0<K,V>{

 public Hashtable<K,V> h=new Hashtable<K,V>();

 public void put(K k, V v) {

h.put(k,v);

 }

 public V get(K k) {

return h.get(k);

 }

 public static void main(String args[]){

TestGen0<String,String> t=new TestGen0<String,String>();

t.put("key", "value");

String s=t.get("key");

System.out.println(s);

 }

}

正確輸出:value

這只是個例子(Java中集合框架都泛型化了,這里費了2遍事.),不過看看是不是創(chuàng)建一個用類型作為參數(shù)的類,參數(shù)是K,V,傳入的“值”是String類型。這個類他沒有特定的待處理型別,以前我們定義好了一個類,在輸入輸入?yún)?shù)有所固定,是什么型別的有要求,但是現(xiàn)在編寫程序,完全可以不制定參數(shù)的類型,具體用的時候來確定,增加了程序的通用性,像是一個模板。

呵呵,類似C++的模板(類似)。

1.1. 泛型通配符

下面我們先看看這些程序:

//Code list 2

void TestGen0Medthod1(List l) {

 for (Object o : l)

System.out.println(o);

}

看看這個方法有沒有異議,這個方法會通過編譯的,假如你傳入String,就是這樣List<String>。

接著我們調(diào)用它,問題就出現(xiàn)了,我們將一個List<String>當(dāng)作List傳給了方法,JVM會給我們一個警告,說這個破壞了類型安全,因為從List中返回的都是Object類型的,而讓我們再看看下面的方法。

//Code list 3

void TestGen0Medthod1(List<String> l) {

 for (Object o : l)

System.out.println(o);

}

因為這里的List<String>不是List<Object>的子類,不是String與Object的關(guān)系,就是說List<String>不隸屬于list<Object>,他們不是繼承關(guān)系,所以是不行的,這里的extends是表示限制的。

類型通配符是很神奇的,List<?>這個你能為他做什么呢?怎么都是“?”,它似乎不確定,他總不能返回一個?作為類型的數(shù)據(jù)吧,是啊他是不會返回一個“?”來問程序員的?JVM會做簡單的思考的,看看代碼吧,更直觀些。

//code list 4

List<String> l1 = new ArrayList<String>();

li.add(“String”);

List<?> l2 = l1;

System.out.println(l1.get(0));

這段代碼沒問題的,l1.get(0)將返回一個Object。

1.2. 編寫泛型類要注意:

1) 在定義一個泛型類的時候,在 “<>”之間定義形式類型參數(shù),例如:“class TestGen<K,V>”,其中“K” , “V”不代表值,而是表示類型。

2) 實例化泛型對象的時候,一定要在類名后面指定類型參數(shù)的值(類型),一共要有兩次書寫。例如:

TestGen<String,String> t=new TestGen<String,String>();

3) 泛型中<K extends Object>,extends并不代表繼承,它是類型范圍限制。

2、泛型與數(shù)據(jù)類型轉(zhuǎn)換

2.1. 消除類型轉(zhuǎn)換

上面的例子大家看到什么了,數(shù)據(jù)類型轉(zhuǎn)換的代碼不見了。在以前我們經(jīng)常要書寫以下代碼,如:

//code list 5

import Java.util.Hashtable;

class Test {

 public static void main(String[] args) {

Hashtable h = new Hashtable();

h.put("key", "value");

String s = (String)h.get("key");

System.out.println(s);

 }

}

這個我們做了類型轉(zhuǎn)換,是不是感覺很煩的,并且強制類型轉(zhuǎn)換會帶來潛在的危險,系統(tǒng)可能會拋一個ClassCastException異常信息。在JDK5.0中我們完全可以這么做,如:

//code list 6

import Java.util.Hashtable;

class Test {

 public static void main(String[] args) {

Hashtable<String,Integer> h = new Hashtable<String,Integer> ();

h.put("key", new Integer(123));

int s = h.get("key").intValue();

System.out.println(s);

 }

}

這里我們使用泛化版本的HashMap,這樣就不用我們來編寫類型轉(zhuǎn)換的代碼了,類型轉(zhuǎn)換的過程交給編譯器來處理,是不是很方便,而且很安全。上面是String映射到String,也可以將Integer映射為String,只要寫成HashTable<Integer,String> h=new HashTable<Integer,String>();h.get(new Integer(0))返回value。果然很方便。

當(dāng)前題目:java高端代碼泛型 java泛型高級使用
分享路徑:http://bm7419.com/article34/ddehsse.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供動態(tài)網(wǎng)站、網(wǎng)頁設(shè)計公司商城網(wǎng)站、電子商務(wù)品牌網(wǎng)站設(shè)計、服務(wù)器托管

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都seo排名網(wǎng)站優(yōu)化