首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 泛型完整教學:從基礎語法到實戰應用

     編輯:Java 相關知識

Java 泛型核心概念與實戰指南

理解 Java 泛型最簡單的方式,是將其視為一種方便的語法糖,能省去手動進行類型轉換的麻煩:

List<Apple> box = ...;
Apple apple = box.get(0); // 無需強制轉型

若無泛型,程式碼必須寫成:

List box = ...;
Apple apple = (Apple) box.get(0); // 需要手動轉型

泛型的核心優在於:讓編譯器保存參數類型資訊、執行類型檢查、自動處理類型轉換。編譯器保證這些轉換的正確性,避免了執行時期才發現的 ClassCastException,大幅提升程式碼安全性與可維護性。

泛型的構成要素

泛型引入了類型變數的概念,依據 Java 語言規範,類型變數出現在以下四種宣告中:

  • 泛型類別宣告
  • 泛型介面宣告
  • 泛型方法宣告
  • 泛型建構子宣告

泛型類別與介面

當一個類別或介面擁有一個或多個類型變數時,它就是泛型。類型變數由尖括號界定,置於類別或介面名稱之前:

public interface List<T> extends Collection<T> { ... }

類型變數的角色如同參數,提供給編譯器進行類型檢查的資訊。Java 類別庫中的眾多類別(如整個 Collection 框架)都已泛型化。例如 List<Apple> 中的 get 方法實際上返回 T 類型物件,編譯器會自動進行類型轉換。

泛型方法與建構子

方法與建構子若宣告了一或多個類型變數,同樣可泛型化:

public static <T> T getFirst(List<T> list)

類型安全的寫入與讀取

// 寫入:編譯器阻擋錯誤類型
List<String> str = new ArrayList<>();
str.add("Hello ");
str.add("World.");
// str.add(1); // 編譯錯誤

// 讀取:自動獲得正確類型
String myString = str.get(0);

// 遍歷:Iterator 亦泛型化
for (Iterator<String> iter = str.iterator(); iter.hasNext();) {
    String s = iter.next();
    System.out.print(s);
}

// 增強 for 迴圈
for (String s : str) {
    System.out.print(s);
}

自動裝箱與拆箱

使用泛型時,autoboxing/autounboxing 會自動發生:

List<Integer> ints = new ArrayList<>();
ints.add(0); // 自動裝箱 int -> Integer
ints.add(1);
int sum = 0;
for (int i : ints) { // 自動拆箱 Integer -> int
    sum += i;
}

注意:裝箱/拆箱會帶來效能損耗,需謹慎使用。

泛型的規則與限制

  1. 類型參數只能是類別類型(含自訂類別),不能是基本類型。
  2. 同一泛型對應多個版本(參數類型不確定),不同版本實例不相容。
  3. 類型參數可有多個(如 Map<K, V>)。
  4. 參數類型可用 extends 限定上界(有界類型)。
  5. 參數類型可為通配符(如 ?、? extends T、? super T)。

對比範例:有無泛型的差異

範例一:使用泛型

public class Gen<T> {
    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 showType() {
        System.out.println("T 的實際類型是: " + ob.getClass().getName());
    }
}

public class GenDemo {
    public static void main(String[] args) {
        Gen<Integer> intOb = new Gen<>(88);
        intOb.showType();
        int i = intOb.getOb(); // 無需轉型
        System.out.println("value= " + i);

        Gen<String> strOb = new Gen<>("Hello Gen!");
        strOb.showType();
        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 showType() {
        System.out.println("實際類型是: " + ob.getClass().getName());
    }
}

public class GenDemo2 {
    public static void main(String[] args) {
        Gen2 intOb = new Gen2(88); // 自動裝箱
        intOb.showType();
        int i = (Integer) intOb.getOb(); // 必須強制轉型
        System.out.println("value= " + i);

        Gen2 strOb = new Gen2("Hello Gen!");
        strOb.showType();
        String s = (String) strOb.getOb(); // 必須強制轉型
        System.out.println("value= " + s);
    }
}

兩者執行結果相同,但泛型版本在編譯期保證類型安全,程式碼更簡潔、可讀性更高。掌握這點,基本泛型應用與程式碼閱讀即無障礙。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved