一、Java 中為什麼會引入泛型?
Java 引入泛型的主要目的是為了提高代碼的類型安全性和可讀性。在 Java 5 之前,集合架構中的容器可以存儲任意類型的對象,這就使得程式員需要在運作時進行類型轉換,容易引發類型轉換異常。而引入泛型後,集合架構中的容器可以限定存儲的元素類型,使得程式員可以在編譯時進行類型檢查,避免了類型轉換異常的發生。此外,泛型還可以提高代碼的可讀性和可維護性,使得代碼更易于了解和修改。泛型的引入使得 Java 語言更加類型安全,更加适合大規模軟體開發。
接下來我們舉個例子說明為什麼: 假設有一個需求,需要編寫一個方法,用于比較兩個對象是否相等。最初的實作可能是這樣的。
java複制代碼public static boolean compareObject(String s1, String s2) {
return s1.equals(s2);
}
但是入參不一定是 String,也有可能是 int、long 等,那麼該怎麼寫呢?難道每個都寫一遍?
java複制代碼public static boolean compareObject(String s1, String s2) {
return s1.equals(s2);
}
public static boolean compareObject(Integer s1, Integer s2) {
return s1.equals(s2);
}
這樣的代碼可讀性,可維護性都很差,于是我們用泛型進行改進, 一個方法就搞定了。
java複制代碼public static <T> boolean compareObjects(T o1, T o2) {
return o1.equals(o2);
}
二、泛型的應用
泛型是 Java 中的一個重要特性,它可以讓我們編寫更加通用、可複用的代碼。
java複制代碼package com.pany.camp.base;
public class Genericity<T, U> {
private T first;
private U second;
public Genericity(T first, U second) {
this.first = first;
this.second = second;
}
public T getFirst() {
return first;
}
public U getSecond() {
return second;
}
public void setFirst(T first) {
this.first = first;
}
public void setSecond(U second) {
this.second = second;
}
@Override
public String toString() {
return "(" + first + ", " + second + ")";
}
}
這個示例中定義了一個泛型類 Genericity,它有兩個類型參數 T 和 U,分别表示 Genericity 中的兩個元素的類型。Genericity類有一個構造函數,用于初始化 Genericity對象的兩個元素。Genericity 類還有一些方法,用于擷取和設定 Genericity 對象的元素,以及将 Genericity 對象轉換成字元串表示。
java複制代碼package com.pany.camp.base;
public class GenericityMain {
public static void main(String[] args) {
Genericity<String, Integer> pair = new Genericity<>("Hello", 123);
// 輸出:(Hello, 123)
System.out.println(pair);
}
}
它的第一個元素是一個字元串,第二個元素是一個整數。使用泛型可以讓我們編寫更加通用、可複用的代碼,可以在不同的場景中使用相同的類來處理不同類型的資料。
三、泛型接口
java複制代碼package com.pany.camp.base;
public interface Pair<T, U> {
T getFirst();
U getSecond();
}
我們定義了一個泛型接口 Pair,它有兩個類型參數 T 和 U,分别表示 Pair 中的兩個元素的類型。Pair 接口有兩個方法,getFirst() 和 getSecond(),用于擷取 Pair 對象的兩個元素。
java複制代碼package com.pany.camp.base;
public class StringIntegerPair implements Pair<String, Integer> {
private String first;
private Integer second;
public StringIntegerPair(String first, Integer second) {
this.first = first;
this.second = second;
}
@Override
public String getFirst() {
return first;
}
@Override
public Integer getSecond() {
return second;
}
}
然後我們建立了一個 StringIntegerPair 類,它實作了 Pair 接口,并指定了 T 和 U 的具體類型為 String 和 Integer。StringIntegerPair 類有一個構造函數,用于初始化 StringIntegerPair 對象的兩個元素。StringIntegerPair 類還實作了 Pair 接口的兩個方法,用于擷取 StringIntegerPair 對象的兩個元素。
四、泛型方法
泛型方法可以讓我們編寫更加通用、可複用的代碼,可以在不同的場景中使用相同的方法來處理不同類型的資料。
例子如下:
bash複制代碼public static <T> int countOccurrences(T[] array, T element) {
int count = 0;
for (T value : array) {
if (value.equals(element)) {
count++;
}
}
return count;
}
我們定義了一個泛型方法 countOccurrences,它有兩個參數,一個是泛型類型數組 array,另一個是泛型類型元素 element。countOccurrences 方法的作用是統計數組中與 element 相等的元素個數。
bash複制代碼String[] strings = {"foo", "bar", "baz", "foo"};
int count1 = countOccurrences(strings, "foo"); // 傳回 2
int count2 = countOccurrences(strings, "qux"); // 傳回 0
Integer[] integers = {1, 2, 3, 2, 1};
int count3 = countOccurrences(integers, 2); // 傳回 2
int count4 = countOccurrences(integers, 4); // 傳回 0
我們分别使用了字元串類型數組和整數類型數組來調用 countOccurrences 方法,傳入不同的元素來統計數組中相等的元素個數。
五、泛型的上下限
泛型的上下限是指在使用泛型時,可以限制泛型參數的類型範圍,進而提高代碼的類型安全性。上限限制了泛型參數的類型必須是某個類或其子類,下限限制了泛型參數的類型必須是某個類或其父類。 使用泛型的上下限可以避免類型轉換錯誤,提高代碼的類型安全性。
在 Java 中,可以使用 extends 關鍵字來指定泛型的上限,使用 super 關鍵字來指定泛型的下限。例如:
bash複制代碼public class Box<T> {
private T item;
public void setItem(T item) {
this.item = item;
}
public T getItem() {
return item;
}
}
// 使用 extends 指定泛型的上限
public class NumberBox<T extends Number> {
private T item;
public void setItem(T item) {
this.item = item;
}
public T getItem() {
return item;
}
}
// 使用 super 指定泛型的下限
public class IntegerBox<T super Integer> {
private T item;
public void setItem(T item) {
this.item = item;
}
public T getItem() {
return item;
}
}
NumberBox 類使用 extends 指定泛型參數的上限為 Number 類型及其子類,是以隻能使用 Number 類型及其子類作為泛型參數。而 IntegerBox 類使用 super 指定泛型參數的下限為 Integer 類型及其父類,是以隻能使用 Integer 類型及其父類作為泛型參數。
作者:激流丶
連結:https://juejin.cn/post/7241765112921735227