天天看點

java泛型 算法_一篇好文章告訴你如何使用Java泛型?

原标題:一篇好文章告訴你如何使用Java泛型?

隻要了解了泛型的一般使用情況就能夠解決多半的問題。是以,首先我們來了解一下什麼是泛型、為什麼要使用它以及應用方法。

什麼是泛型?

試想一個簡單的添加方法(method),如下:

java泛型 算法_一篇好文章告訴你如何使用Java泛型?

long,float 或 double 類型并不能當作輸入傳給這個方法。

如果從該方法中抽象出資料類型,就可以得到一個新的方式,如下。

在這裡,是 泛型參數(也稱為類型變量),和給某一方法聲明的參數一樣。給 或 傳遞的泛型參數的值,與方法參數相似,叫做類型參數。

java泛型 算法_一篇好文章告訴你如何使用Java泛型?

現在考慮資料結構,簡單起見,我們來想一想數組。我們能夠建立一個任意類型的數組嗎?不可以。我們隻能建立一個整數數組、浮點數數組或者其他一種特定類型的數組。好了,忘掉所有程式設計語言裡實作數組的方法,然後問一個問題:“我們是否可以從這個資料結構中抽象出一種資料類型?”

答案是肯定的。Java 中的 ArrayList 就是做這件事的一種類。通過 List = new ArrayList<>(); 就能建立一個字元串數組,當整數作為類型參數時,它就是整數數組,其他的也類似。

雖然我們用 ArrayList 作為例子,但由于其複雜性,我們不會讨論他們具體是怎麼實作的。我們會借鑒一個盒子并思考怎麼把這個盒子做出來,而這個盒子就是某個特定類型的通用架構(a Generic box from a Specific Typed box)。

java泛型 算法_一篇好文章告訴你如何使用Java泛型?

思考以下代碼,将一個字元串放進特定字元串架構(SpecifizedStringBox)對象中,然後以此獲得一個字元串。

java泛型 算法_一篇好文章告訴你如何使用Java泛型?

現在,如果從該對象中抽取其資料類型“Type”,就得到一個由以下代碼代表的通用架構(GenericBox,也就是泛型),而該架構可以使用 String、Integer、Boolean 等任意資料類型。

java泛型 算法_一篇好文章告訴你如何使用Java泛型?

是以,使用泛型,就是要從某個方法(method)或者類(class)中,抽象出一種适用于任意類型的通用方法/類。

為什麼要用泛型?

簡單點的答案就是,通過泛型抽象資料類型後,你的代碼可以重複使用并且易于維護。

泛型應用在什麼地方?

看起來似乎通過重構已有特定類型的方法或架構,就能應用泛型。在處理資料結構和原始資料類型時,似乎還挺容易,但是我們總會在各不相同的類中建立大量的資料類型。泛型程式設計模式(Generic Programming Paradigm)和 面向對象程式設計(OOP)混合在一起時,就很難決定是否要使用泛型。了解在哪裡應用泛型,問題就解決了一半。

本文就将帶你了解一些典型的泛型用例,包括其使用場景,也可以讓你在遇到同類型問題時能夠合理應用泛型。

Java 在 JDK 5.0 中引用泛型的目的在于:

類型安全性(Type safety):一旦使用類型參數後,在該方法或架構中就不存在其他的資料類型,同時也避免了類型轉化的需求;

通用程式設計及參數的多态性。

C++ 的模版程式設計能幫我們實作通用程式設計及參數的多态性,根據資料的類型(預定義或使用者定義的)轉化同樣的算法模型,達到複用同一個代碼或程式的目的。在 Java 中也可以使用類似的方法。

現在來看一下幾個常用的泛型用例。

用例 1 : 泛型的第一級别用法是算法和資料類型

算法和資料結構并行,資料類型的微小變化可能會改變一個算法的複雜性。

資料結構中的資料有類型,用泛型将這種類型抽取出來,可以作為類型參數。而算法的輸入參數也具有資料類型,同樣,通過泛型可以将該類型從輸入參數中抽象出來。是以,泛型适用于使用特定資料結構的任意一種算法。

不過事實上,泛型主要用于 Java 的集合 API。

如果你自己寫資料結構,那麼一定試試利用泛型。除了Java 的集合 API,你也會在 Guava、Apache Common Collection、FastUtils、JCtools 和 Eclipse Collection 裡發現其他對泛型更好的應用。

用例 2 :數值輸入框或者單個元素的容器

具備可通用類型的資料結構,可以稱之為泛型架構(Generics Boxes)。例如 ArrayList、LinkedList 等等這樣的類就代表資料類型,同時為他們同類型的資料起着泛型架構的作用。

有時候,通用架構以單個元素而不是集合的形式出現。諸如 Map 映射中的輸入 ,節點 ,資料對 ,以及其他代數資料類型,像是可選項 , 選擇 等等,它們隻作為特定類型資料的依托(Holder)或封裝器(wrapper)而已。

ThreadLocal 和 AtomicReference 在适用于并發通路算法的單元素容器中,是非常好的例子。

類似的用法有時合理,而有一些則不太适

用。 一個盒子在早期确實可以容納任何類型的物品,但現在會将其進行分類:這個盒子用來裝玩具,而下一個盒子用來裝筆,等等。

杯子是很好的例子,可以把它比做實時對象類型的依托物(Holder),它可以裝茶、咖啡或者任何飲料。公交上可以坐男人和女人,如果讓公交具備類型安全性且隻允許女人上車,那麼我們可以稱之為女士公交。這種比喻可能有點欠妥,但它提出了商業用例,尤其是封裝器或者依托物也具有應用泛型的可能。嘗試詢問業務的封裝或依托是否有使用資料結構的傾向,如果有,那麼使用泛型會更好。

用例類型 3 :抽象類型的泛型工具方法

泛型算法不一定總是和特定的資料結構或算法綁定在一起。有時,基于實際應用的滿意度,它還可以應用在大多數抽象資料結構組中。

在 Java 中就有該Collections工具類。

檢視以下方法,了解什麼方法能适用:

Collection Factories Methods, Empty/Singleton

emptyList, emptyMap, emptySet

singleton, singletonList, singletonMap

封裝方法(Synchronized, UnModifiable, Checked Collection):

synchronizedCollection, synchronizedSet, synchronizedMap

unmodifiableCollection, unmodifiableSet, unmodifiableList

checkedCollection, checkedList, checkedSet

還有一些泛型方法,可歸為四大類:

1. 更改清單中的元素順序:reverse,rotate,shuffle,sort,swap;

2. 更改清單内容:copy, fill, replaceAll;

3. 在集合中尋找極值:最大值,最小值;

4. 在清單中查找特定值:binarySearch,indexOfSubList,lastIndexOfSubList。

由于他們适用于清單中的任意類型,這些都是可複用的功能。我們會發現,大多數集合都适用泛型方法。

用例類型 4 :泛型方法用于類的分層并行結構中

Spring 架構中的 JpaRepository、CrudRepository 都已使用泛型建構,建立、更新、查找、查找所有、删除等等,是适用于所有實體的泛型方法。

需要給每個實體建立一個并行資料通路對象(DAO)類時,會出現類的分層并行結構(parallel hierarchy of classes)。 不過 DAO 模式并不是其出現的唯一情況。

如果為了提供更多可能的方法執行個體,我們可以通過将方法與對象解除聯系的方式,來應用政策模式(Strategy Pattern)處理業務問題,這時類的分層并行結構就會出現。

每當我們添加一個新類,就會增加一個并行的測試用例。如果需要工廠,我們就添加一個并行工廠類。 類的分層并行結構出現在業務用例中。試想一輛新車,比如“大巴車”,把它添加到以下的車輛層級中時,可能還需要添加一個“大巴車司機”的類。

java泛型 算法_一篇好文章告訴你如何使用Java泛型?

來看以下分層并行類和其泛型的例子:

java泛型 算法_一篇好文章告訴你如何使用Java泛型?
java泛型 算法_一篇好文章告訴你如何使用Java泛型?

用例類型 5 : 建立類型安全的異構容器

集合 是均質容器的一個示例,任何字元串以外的東西都不能放進該架構裡。

而集合 是異構容器的一個例子,可以放入任意對象。集合 便不是類型安全的,需要檢查類型、進行轉換,類似于原始類型的集合(原始類型是沒有泛型類型參數的通用類型,它将對象視為預設的類型參數)。Java 沒有為類型安全的異構容器提供第一級别的支援。

在集合 中,類型參數“String”被用作類型參數“T”,以確定類型安全。但是對于 Map,它卻有兩個類型參數,通過之前Java 集合 API 的例子,通常泛型會限制每個容器類型參數的數量為一個定值。可以将類型參數設定在Map映射的鍵(key)上,而不是容器上,進而繞過這個限制。在建立類型安全的異構容器/Map映射時,利用類對象作為鍵。

像是 bean 容器,異常處理程式容器,或服務查找容器都是異構容器的示例,都可以使用泛型來進行類型安全化,方法既使用類對象作為鍵實作動态轉換。傳回搜狐,檢視更多

責任編輯: