泛型
泛型让代码更安全、更灵活,本课学习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类型,可以读写。📖 小节
- 泛型让代码更安全、更灵活
- 泛型类、泛型方法、泛型接口
- 通配符:
?、? extends、? super - 类型擦除:编译后泛型信息被擦除
📝 作业
- 泛型容器: 实现一个泛型栈(Stack)类
- 泛型方法: 实现一个泛型方法,将数组转换为List
- 有界泛型: 实现一个方法,比较两个对象的大小
下一课
下一课我们将学习 实战:集合应用,综合运用集合知识。



