泛型

泛型让代码更安全、更灵活,本课学习Java泛型的使用。

什么是泛型

泛型是参数化类型,让类和方法可以操作多种类型。

泛型的好处

好处 说明
类型安全 编译时检查类型
代码复用 一份代码适用多种类型
消除强制转换 不需要手动转型

泛型类

语法

JAVA
public class 类名<T> {
    // 使用T作为类型
}

示例:泛型类

JAVA
public class Box<T> {
    private T value;
    
    public void set(T value) {
        this.value = value;
    }
    
    public T get() {
        return value;
    }
    
    public static void main(String[] args) {
        // 存储Integer
        Box<Integer> intBox = new Box<>();
        intBox.set(100);
        int num = intBox.get();  // 不需要强制转换
        
        // 存储String
        Box<String> strBox = new Box<>();
        strBox.set("Hello");
        String str = strBox.get();
        
        System.out.println("Integer Box: " + num);
        System.out.println("String Box: " + str);
    }
}
▶ 试一试

多个泛型参数

JAVA
public class Pair<K, V> {
    private K key;
    private V value;
    
    public Pair(K key, V value) {
        this.key = key;
        this.value = value;
    }
    
    public K getKey() { return key; }
    public V getValue() { return value; }
    
    @Override
    public String toString() {
        return key + "=" + value;
    }
    
    public static void main(String[] args) {
        Pair<String, Integer> pair = new Pair<>("Alice", 95);
        System.out.println(pair);  // Alice=95
    }
}

泛型方法

语法

JAVA
public static <T> 方法名(参数) {
    // 使用T
}

示例:泛型方法

JAVA
public class GenericMethod {
    public static <T> void printArray(T[] array) {
        for (T element : array) {
            System.out.print(element + " ");
        }
        System.out.println();
    }
    
    public static <T> T getFirst(T[] array) {
        if (array == null || array.length == 0) {
            return null;
        }
        return array[0];
    }
    
    public static <T extends Comparable<T>> T getMax(T[] array) {
        T max = array[0];
        for (T element : array) {
            if (element.compareTo(max) > 0) {
                max = element;
            }
        }
        return max;
    }
    
    public static void main(String[] args) {
        Integer[] nums = {1, 2, 3, 4, 5};
        String[] names = {"Alice", "Bob", "Charlie"};
        
        printArray(nums);    // 1 2 3 4 5
        printArray(names);   // Alice Bob Charlie
        
        System.out.println("第一个数:" + getFirst(nums));  // 1
        System.out.println("第一个名字:" + getFirst(names));  // Alice
        
        System.out.println("最大值:" + getMax(nums));  // 5
        System.out.println("最大名字:" + getMax(names));  // Charlie
    }
}
▶ 试一试

泛型接口

定义泛型接口

JAVA
public interface Repository<T> {
    void add(T item);
    T get(int index);
    List<T> getAll();
}

实现泛型接口

JAVA
public class ArrayListRepository<T> implements Repository<T> {
    private List<T> list = new ArrayList<>();
    
    @Override
    public void add(T item) {
        list.add(item);
    }
    
    @Override
    public T get(int index) {
        return list.get(index);
    }
    
    @Override
    public List<T> getAll() {
        return new ArrayList<>(list);
    }
    
    public static void main(String[] args) {
        Repository<String> repo = new ArrayListRepository<>();
        repo.add("Alice");
        repo.add("Bob");
        System.out.println(repo.getAll());  // [Alice, Bob]
    }
}

泛型通配符

无界通配符 ?

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

上界通配符 ? extends T

JAVA
// 只接受Number及其子类
public static double sum(List<? extends Number> list) {
    double total = 0;
    for (Number num : list) {
        total += num.doubleValue();
    }
    return total;
}

下界通配符 ? super T

JAVA
// 只接受Integer及其父类
public static void addNumbers(List<? super Integer> list) {
    list.add(1);
    list.add(2);
    list.add(3);
}

示例:通配符

JAVA
import java.util.ArrayList;
import java.util.List;

public class WildcardDemo {
    // 无界通配符
    public static void printList(List<?> list) {
        for (Object item : list) {
            System.out.print(item + " ");
        }
        System.out.println();
    }
    
    // 上界通配符
    public static double sum(List<? extends Number> list) {
        double total = 0;
        for (Number num : list) {
            total += num.doubleValue();
        }
        return total;
    }
    
    public static void main(String[] args) {
        List<Integer> ints = new ArrayList<>();
        ints.add(1);
        ints.add(2);
        ints.add(3);
        
        List<String> strs = new ArrayList<>();
        strs.add("Alice");
        strs.add("Bob");
        
        printList(ints);  // 1 2 3
        printList(strs);  // Alice Bob
        
        System.out.println("sum: " + sum(ints));  // 6.0
    }
}
▶ 试一试

类型擦除

Java泛型是通过类型擦除实现的,编译后泛型信息会被擦除。

JAVA
// 编译前
List<String> list = new ArrayList<>();
list.add("Hello");

// 编译后(类型擦除)
List list = new ArrayList();
list.add("Hello");
String str = (String) list.get(0);  // 自动添加强制转换
⚠️ 注意: 运行时无法获取泛型的类型信息。List<String>List<Integer>在运行时是同一个类型。

泛型约束

示例:有界泛型

JAVA
// T必须实现Comparable接口
public static <T extends Comparable<T>> T min(T a, T b) {
    return a.compareTo(b) <= 0 ? a : b;
}

// T必须是Number的子类
public static <T extends Number> double doubleValue(T num) {
    return num.doubleValue();
}
▶ 试一试

常见泛型命名

名称 含义
T Type(类型)
E Element(元素)
K Key(键)
V Value(值)
N Number(数字)

❓ 常见问题

Q 为什么用泛型?
A 类型安全、代码复用、消除强制转换。
Q 泛型支持基本类型吗?
A 不支持,要用包装类。如List<int>改为List<Integer>
Q <?><Object>有什么区别?
A <?>是未知类型,只能读不能写。<Object>是Object类型,可以读写。

📖 小节

📝 作业

  1. 泛型容器: 实现一个泛型栈(Stack)类
  2. 泛型方法: 实现一个泛型方法,将数组转换为List
  3. 有界泛型: 实现一个方法,比较两个对象的大小

下一课

下一课我们将学习 实战:集合应用,综合运用集合知识。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏