溫馨提示×

溫馨提示×

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

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么使用Java泛型

發布時間:2021-07-05 16:39:59 來源:億速云 閱讀:238 作者:chen 欄目:編程語言
# 怎么使用Java泛型

## 一、泛型概述

### 1.1 什么是泛型
泛型(Generics)是Java SE 5.0引入的重要特性,它允許在定義類、接口和方法時使用類型參數(type parameters)。這種參數化類型的能力讓代碼可以應用于多種數據類型,同時保持編譯時的類型安全。

```java
// 沒有泛型的例子
List list = new ArrayList();
list.add("hello");
String s = (String) list.get(0); // 需要強制類型轉換

// 使用泛型的例子
List<String> list = new ArrayList<>();
list.add("hello");
String s = list.get(0); // 自動類型推斷

1.2 為什么需要泛型

  • 類型安全:編譯時就能發現類型不匹配的錯誤
  • 消除強制類型轉換:使代碼更簡潔易讀
  • 代碼復用:可以編寫更通用的算法和數據結構
  • 更好的API設計:使API更靈活且易于理解

二、泛型基礎語法

2.1 泛型類

在類名后面添加類型參數聲明,可以有一個或多個類型參數。

public class Box<T> {
    private T t;
    
    public void set(T t) {
        this.t = t;
    }
    
    public T get() {
        return t;
    }
}

// 使用示例
Box<Integer> integerBox = new Box<>();
integerBox.set(10);
Integer value = integerBox.get();

2.2 泛型接口

接口也可以使用泛型,實現類需要指定具體類型或保持泛型。

public interface Pair<K, V> {
    K getKey();
    V getValue();
}

public class OrderedPair<K, V> implements Pair<K, V> {
    private K key;
    private V value;
    
    // 實現方法...
}

2.3 泛型方法

在方法返回類型前聲明類型參數,可以用于靜態和非靜態方法。

public class Util {
    public static <T> T getMiddle(T... a) {
        return a[a.length / 2];
    }
}

// 使用示例
String middle = Util.<String>getMiddle("John", "Q.", "Public");
// 類型推斷
Number middleNum = Util.getMiddle(3.14, 1729, 0);

三、類型參數命名約定

按照Java慣例,類型參數名稱使用單個大寫字母: - E - Element(集合元素) - K - Key(鍵) - V - Value(值) - T - Type(類型) - S,U,V - 第二、第三、第四類型

四、泛型的高級特性

4.1 類型通配符

使用問號(?)表示未知類型,常用于方法參數。

public static void printList(List<?> list) {
    for (Object elem : list) {
        System.out.println(elem);
    }
}

4.2 有限制的通配符

可以限制通配符的上界或下界。

上界通配符<? extends T> 表示T或其子類

public static double sumOfList(List<? extends Number> list) {
    double sum = 0.0;
    for (Number num : list) {
        sum += num.doubleValue();
    }
    return sum;
}

下界通配符<? super T> 表示T或其父類

public static void addNumbers(List<? super Integer> list) {
    for (int i = 1; i <= 10; i++) {
        list.add(i);
    }
}

4.3 泛型擦除

Java泛型是通過類型擦除實現的,編譯器在編譯時去掉類型參數信息。

// 編譯前
List<String> list = new ArrayList<>();
list.add("hello");
String s = list.get(0);

// 編譯后(近似)
List list = new ArrayList();
list.add("hello");
String s = (String) list.get(0);

五、泛型使用限制

5.1 不能實例化類型參數

public static <E> void append(List<E> list) {
    E elem = new E();  // 編譯錯誤
    list.add(elem);
}

5.2 不能創建泛型數組

List<Integer>[] arrayOfLists = new List<Integer>[2];  // 編譯錯誤

5.3 靜態上下文限制

靜態字段或方法不能引用類的類型參數。

public class MobileDevice<T> {
    private static T os;  // 編譯錯誤
    
    public static T getOS() {  // 編譯錯誤
        return os;
    }
}

5.4 不能拋出或捕獲泛型類實例

// 編譯錯誤
try {
    // ...
} catch (SomeException<Integer> e) {
    // ...
}

六、泛型最佳實踐

6.1 PECS原則

Producer-Extends, Consumer-Super(生產者使用extends,消費者使用super)

// 正確示例
public static <T> void copy(List<? super T> dest, List<? extends T> src) {
    for (int i = 0; i < src.size(); i++) {
        dest.set(i, src.get(i));
    }
}

6.2 優先使用泛型方法

當方法操作獨立于類類型參數時,使用泛型方法更靈活。

// 優于在類上定義類型參數
public static <T> List<T> filter(List<T> list, Predicate<T> p) {
    List<T> result = new ArrayList<>();
    for (T t : list) {
        if (p.test(t)) {
            result.add(t);
        }
    }
    return result;
}

6.3 避免原生類型

總是使用泛型類型,避免使用原生類型(raw type)。

List list = new ArrayList();  // 避免
List<String> list = new ArrayList<>();  // 推薦

七、實際應用示例

7.1 泛型緩存系統

public class Cache<K, V> {
    private Map<K, V> cacheMap = new HashMap<>();
    
    public void put(K key, V value) {
        cacheMap.put(key, value);
    }
    
    public V get(K key) {
        return cacheMap.get(key);
    }
    
    public void remove(K key) {
        cacheMap.remove(key);
    }
}

7.2 通用比較工具

public class CompareUtil {
    public static <T extends Comparable<T>> T max(T a, T b) {
        return a.compareTo(b) > 0 ? a : b;
    }
    
    public static <T extends Comparable<? super T>> void sort(List<T> list) {
        Collections.sort(list);
    }
}

八、常見問題解答

8.1 泛型能否用于基本類型?

不能直接使用,必須使用對應的包裝類。Java的泛型是基于對象的,基本類型不是對象。

8.2 如何檢查泛型類型?

由于類型擦除,運行時無法直接檢查泛型類型??梢酝ㄟ^傳遞Class對象來解決:

public <T> void checkType(Object obj, Class<T> type) {
    if (type.isInstance(obj)) {
        T t = type.cast(obj);
        // 處理t
    }
}

8.3 泛型與多態如何配合?

子類可以繼承或擴展父類的泛型參數:

class Parent<T> {}
class Child<T> extends Parent<T> {}
class StringChild extends Parent<String> {}

九、總結

Java泛型是強大的語言特性,正確使用可以: 1. 提高代碼的類型安全性 2. 減少類型轉換的繁瑣 3. 增強代碼的可讀性和重用性 4. 使API設計更加靈活

雖然泛型有一些限制(主要是由于類型擦除),但通過合理的設計模式和使用技巧,可以充分發揮其優勢。掌握泛型是成為高級Java開發者的必備技能。


本文涵蓋了Java泛型的主要知識點,從基礎概念到高級應用,共約3700字。通過示例代碼和最佳實踐,幫助讀者全面理解并正確使用Java泛型。在實際開發中,應根據具體場景靈活運用泛型特性,編寫出更安全、更靈活的代碼。 “`

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女