溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Java泛型該怎么掌握

發(fā)布時(shí)間:2022-01-17 16:12:42 來源:億速云 閱讀:172 作者:iii 欄目:編程語言

這篇文章主要介紹“Java泛型該怎么掌握”的相關(guān)知識(shí),小編通過實(shí)際案例向大家展示操作過程,操作方法簡(jiǎn)單快捷,實(shí)用性強(qiáng),希望這篇“Java泛型該怎么掌握”文章能幫助大家解決問題。

數(shù)據(jù)類型轉(zhuǎn)換和錯(cuò)誤

為理解泛型類型為何如此有用,我們要將注意力轉(zhuǎn)向 Java 語言中最容易引發(fā)錯(cuò)誤的因素之一 - 需要不斷地將表達(dá)式向下類型轉(zhuǎn)換(downcast)為比其靜態(tài)類型更為具體的數(shù)據(jù)類型。

程序中的每個(gè)向下類型轉(zhuǎn)換對(duì)于 ClassCastException 而言都是潛在的危險(xiǎn),應(yīng)當(dāng)盡量避免它們。但是在 Java 語言中它們通常是無法避免的,即便在設(shè)計(jì)優(yōu)良的程序中也是如此。

在 Java 語言中進(jìn)行向下類型轉(zhuǎn)換最常見的原因在于,經(jīng)常以專用的方式來使用類,這限制了方法調(diào)用所返回的參數(shù)可能的運(yùn)行時(shí)類型。例如,假定往 Hashtable 中添加元素并從中檢索元素。那么在給定的程序中,被用作鍵的元素類型和存儲(chǔ)在散列表中的值類型,將不能是任意對(duì)象。通常,所有的鍵都是某一特定類型的實(shí)例。同樣地,存儲(chǔ)的值將共同具有比 Object 更具體的公共類型。

但是在目前現(xiàn)有的 Java 語言版本中,不可能將散列表的特定鍵和元素聲明為比 Object 更具體的類型。在散列表上執(zhí)行插入和檢索操作的類型特征符告訴我們只能插入和刪除任意對(duì)象。例如, putget 操作的說明如下所示:


清單 1. 插入/檢索類型說明表明只能是任意對(duì)象

class Hashtable {
  Object put(Object key, Object value) {...}
  Object get(Object key) {...}
  ...
}

因此,當(dāng)我們從類 Hashtable 的實(shí)例檢索元素時(shí),比如,即使我們知道在 Hashtable 中只放了 String ,而類型系統(tǒng)也只知道所檢索的值是 Object 類型。在對(duì)檢索到的值進(jìn)行任何特定于 String 的操作之前,必須將它強(qiáng)制轉(zhuǎn)換為 String ,即使是將檢索到的元素添加到同一代碼塊中,也是如此!


清單 2. 將檢索到的值強(qiáng)制轉(zhuǎn)換成 String

import java.util.Hashtable;
class Test {
  public static void main(String[] args) {
    Hashtable h = new Hashtable();
    h.put(new Integer(0), "value");
    String s = (String)h.get(new Integer(0));
    System.out.println(s);
  }
}

請(qǐng)注意 main 方法主體部分的第三行中需要進(jìn)行的數(shù)據(jù)類型轉(zhuǎn)換。因?yàn)?Java 類型系統(tǒng)相當(dāng)薄弱,因此代碼會(huì)因象上面那樣的數(shù)據(jù)類型轉(zhuǎn)換而漏洞百出。這些數(shù)據(jù)類型轉(zhuǎn)換不僅使 Java 代碼變得更加拖沓冗長,而且它們還降低了靜態(tài)類型檢查的價(jià)值(因?yàn)槊總€(gè)數(shù)據(jù)類型轉(zhuǎn)換都是一個(gè)選擇忽略靜態(tài)類型檢查的偽指令)。我們?cè)撊绾螖U(kuò)展該類型系統(tǒng),從而不必回避它呢?

用泛型類型來解決問題!

要消除如上所述的數(shù)據(jù)類型轉(zhuǎn)換,有一種普遍的方法,就是用 泛型類型來增大 Java 類型系統(tǒng)。可以將泛型類型看作是類型“函數(shù)”;它們通過類型變量進(jìn)行參數(shù)化,這些類型變量可以根據(jù)上下文用各種類型參數(shù)進(jìn)行 實(shí)例化。

例如,與簡(jiǎn)單地定義類 Hashtable 不同,我們可以定義泛型類 Hashtable ,其中 KeyValue 是類型參數(shù)。除了類名后跟著尖括號(hào)括起來的一系列類型參數(shù)聲明之外,在 Tiger 中定義這樣的泛型類的語法和用于定義普通類的語法很相似。例如,可以按照如下所示的那樣定義自己的泛型 Hashtable 類:


清單 3. 定義泛型 Hashtable 類

class Hashtable{ ... }

然后可以引用這些類型參數(shù),就像我們?cè)陬惗x主體內(nèi)引用普通類型那樣,如下所示:


清單 4. 像引用普通類型那樣引用類型參數(shù)

class Hashtable{
  ...
  Value put(Key k, Value v) {...}
  Value get(Key k) {...}
}

類型參數(shù)的作用域就是相應(yīng)類定義的主體部分(除了靜態(tài)成員之外)(在下一篇文章中,我們將討論為何 Tiger 實(shí)現(xiàn)中有這樣的“怪習(xí)”,即必須對(duì)靜態(tài)成員進(jìn)行此項(xiàng)限制。請(qǐng)留意?。?。

創(chuàng)建一個(gè)新的 Hashtable 實(shí)例時(shí),必須傳遞類型參數(shù)以指定 KeyValue 的類型。傳遞類型參數(shù)的方式取決于我們打算如何使用 Hashtable 。在上面的示例中,我們真正想要做的是創(chuàng)建 Hashtable 實(shí)例,它只將 Integer 映射為 String ??梢杂眯碌?Hashtable 類來完成這件事:


清單 5. 創(chuàng)建將 Integer 映射為 String 的實(shí)例

import java.util.Hashtable;
class Test {
  public static void main(String[] args) {
    Hashtableh = new Hashtable();
    h.put(new Integer(0), "value");
    ...
  }
}

現(xiàn)在不再需要數(shù)據(jù)類型轉(zhuǎn)換了。請(qǐng)注意用來實(shí)例化泛型類 Hashtable 的語法。就像泛型類的類型參數(shù)用尖括號(hào)括起來那樣,泛型類型應(yīng)用程序的參數(shù)也是用尖括號(hào)括起來的。


清單 6. 除去不必要的數(shù)據(jù)類型轉(zhuǎn)換

...
String s = h.get("key");
System.out.println(s);

當(dāng)然,程序員若只是為了能使用泛型類型而必須重新定義所有的標(biāo)準(zhǔn)實(shí)用程序類(比如 HashtableList )的話,則可能會(huì)是一項(xiàng)浩大的工程。幸好,Tiger 為用戶提供了所有 Java 集合類的泛型版本,因此我們不必自己動(dòng)手來重新定義它們了。此外,這些類能與舊代碼和新的泛型代碼一起無縫工作(下個(gè)月,我們會(huì)說明如何做到這一點(diǎn))。

Tiger 的基本類型限制

Tiger 中類型變量的限制之一就是,它們必須用引用類型進(jìn)行實(shí)例化 - 基本類型不起作用。因此,在上面這個(gè)示例中,無法完成創(chuàng)建從 int 映射到 StringHashtable 。

這很遺憾,因?yàn)檫@意味著只要您想把基本類型用作泛型類型的參數(shù),您就必須把它們組裝為對(duì)象。另一方面,當(dāng)前的這種情況是最糟的;您不能將 int 作為鍵傳遞給 Hashtable ,因?yàn)樗械逆I都必須是 Object 類型。

我們真正想看到的是,基本類型可以自動(dòng)進(jìn)行包裝(boxing)和解包裝(unboxing),類似于用 C# 所進(jìn)行的操作(或者比后者更好)。遺憾的是,Tiger 不打算包括基本類型的自動(dòng)包裝(但是人們可以一直期待 Java 1.6 中出現(xiàn)該功能?。?/p>

受限泛型

有時(shí)我們想限制可能出現(xiàn)的泛型類的類型實(shí)例化。在上面這個(gè)示例中,類 Hashtable 的類型參數(shù)可以用我們想用的任何類型參數(shù)進(jìn)行實(shí)例化,但是對(duì)于其它某些類,我們或許想將可能的類型參數(shù)集限定為給定類型 范圍內(nèi)的子類型。

例如,我們可能想定義泛型 ScrollPane 類,它引用普通的帶有滾動(dòng)條功能的 Pane 。被包含的 Pane 的運(yùn)行時(shí)類型通常會(huì)是類 Pane 的子類型,但是靜態(tài)類型就只是 Pane

有時(shí)我們想用 getter 檢索被包含的 Pane ,但是希望 getter 的返回類型盡可能具體些。我們可能想將類型參數(shù) MyPane 添加到 ScrollPane 中,該類型參數(shù)可以用 Pane 的任何子類進(jìn)行實(shí)例化。然后可以用這種形式的子句: extends Bound 來說明 MyPane 的聲明,從而來設(shè)定 MyPane 的范圍:


清單 7. 用 extends 子句來說明 MyPane 聲明

class ScrollPane{ ... }

當(dāng)然,我們可以完全不使用顯式的范圍,只要能確保沒有用不適當(dāng)?shù)念愋蛠韺?shí)例化類型參數(shù)。

為什么要自找麻煩在類型參數(shù)上設(shè)定范圍呢?這里有兩個(gè)原因。首先,范圍使我們?cè)黾恿遂o態(tài)類型檢查功能。有了靜態(tài)類型檢查,就能保證泛型類型的每次實(shí)例化都符合所設(shè)定的范圍。

其次,因?yàn)槲覀冎李愋蛥?shù)的每次實(shí)例化都是這個(gè)范圍之內(nèi)的子類,所以可以放心地調(diào)用類型參數(shù)實(shí)例出現(xiàn)在這個(gè)范圍之內(nèi)的任何方法。如果沒有對(duì)參數(shù)設(shè)定顯式的范圍,那么缺省情況下范圍是 Object ,這意味著我們不能調(diào)用范圍實(shí)例在 Object 中未曾出現(xiàn)的任何方法。

多態(tài)方法

除了用類型參數(shù)對(duì)類進(jìn)行參數(shù)化之外,用類型參數(shù)對(duì)方法進(jìn)行參數(shù)化往往也同樣很有用。泛型 Java 編程用語中,用類型進(jìn)行參數(shù)化的方法被稱為 多態(tài)方法(Polymorphic method)。

多態(tài)方法之所以有用,是因?yàn)橛袝r(shí)候,在一些我們想執(zhí)行的操作中,參數(shù)與返回值之間的類型相關(guān)性原本就是泛型的,但是這個(gè)泛型性質(zhì)不依賴于任何類級(jí)的類型信息,而且對(duì)于各個(gè)方法調(diào)用都不相同。

例如,假定想將 factory 方法添加到 List 類中。這個(gè)靜態(tài)方法只帶一個(gè)參數(shù),也將是 List 唯一的元素(直到添加了其它元素)。因?yàn)槲覀兿M?List 成為其所包含的元素類型的泛型,所以希望靜態(tài) factory 方法帶有類型變量 T 這一參數(shù)并返回 List 的實(shí)例。

但是我們確實(shí)希望該類型變量 T 能在方法級(jí)別上進(jìn)行聲明,因?yàn)樗鼤?huì)隨每次單獨(dú)的方法調(diào)用而發(fā)生改變(而且,正如我在下一篇文章中將討論的那樣,Tiger 設(shè)計(jì)的“怪習(xí)”規(guī)定靜態(tài)成員不在類級(jí)類型參數(shù)的范疇之內(nèi))。Tiger 讓我們通過將類型參數(shù)作為方法聲明的前綴,從而在單獨(dú)的方法級(jí)別上聲明類型參數(shù)。例如,可以按照如下所示的那樣為 factory 方法 make 添加前綴:


清單 8. 將類型參數(shù)作為前綴添加到方法聲明

class Utilities {public static Listmake(T first) {
     return new List(first);
   }
}

除了多態(tài)方法中所增加的靈活性之外,Tiger 中還增加了一個(gè)優(yōu)點(diǎn)。Tiger 使用類型推斷機(jī)制,根據(jù)參數(shù)類型來自動(dòng)推斷出多態(tài)方法的類型。這可以大大減少方法調(diào)用的繁瑣和復(fù)雜性。例如,如果想調(diào)用 make 方法來構(gòu)造包含 new Integer(0)List 新實(shí)例,那么只需編寫:


清單 9. 強(qiáng)制 make 構(gòu)造新實(shí)例

Utilities.make(Integer(0))

然后會(huì)自動(dòng)地從方法參數(shù)中推斷出類型參數(shù)的實(shí)例化。

關(guān)于“Java泛型該怎么掌握”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí),可以關(guān)注億速云行業(yè)資訊頻道,小編每天都會(huì)為大家更新不同的知識(shí)點(diǎn)。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI