在 Java 中,泛型(Generics) 是一种提供类型安全和代码复用的机制。它允许你在类、接口和方法中定义类型参数,从而编写更加通用和灵活的代码。
✅ 1. 为什么需要泛型?
在 Java 5 之前,集合类(如 ArrayList
)只能存储 Object
类型,这导致了以下问题:
- 类型不安全:需要强制类型转换,容易出现
ClassCastException
。
- 代码不清晰:无法明确知道集合中存储的具体数据类型。
没有泛型的代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import java.util.ArrayList;
public class Main { public static void main(String[] args) { ArrayList list = new ArrayList(); list.add("Hello"); list.add(123);
String str = (String) list.get(0); System.out.println(str);
String num = (String) list.get(1); } }
|
解决方法:使用泛型
1 2 3 4
| ArrayList<String> list = new ArrayList<>(); list.add("Hello");
String str = list.get(0);
|
✅ 2. 泛型的基本语法
定义泛型类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class Box<T> { private T content;
public void setContent(T content) { this.content = content; }
public T getContent() { return content; } }
public class Main { public static void main(String[] args) { Box<String> stringBox = new Box<>(); stringBox.setContent("泛型示例"); System.out.println("内容: " + stringBox.getContent()); } }
|
解释:
<T>
:表示泛型类型,T
是一个占位符,可以用任意字母代替。
Box<String>
:指定泛型类型为 String
,确保类型安全。
✅ 3. 泛型方法
泛型不仅可以用于类,还可以用于方法。
泛型方法示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class Main {
public static <T> void printArray(T[] array) { for (T element : array) { System.out.print(element + " "); } System.out.println(); }
public static void main(String[] args) { Integer[] intArray = {1, 2, 3}; String[] strArray = {"Java", "Python", "C++"};
printArray(intArray); printArray(strArray); } }
|
解释:
<T>
:在方法返回类型之前声明。
T[] array
:泛型数组参数。
- 方法可以接受任意类型的数组。
✅ 4. 泛型的类型边界
有时候我们需要对泛型的类型进行限制,Java 提供了两种方式:
(1) 上界通配符: <? extends T>
- 适用于读取数据。
- 表示类型必须是
T
或 T
的子类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import java.util.*;
public class Main { public static void printNumbers(List<? extends Number> list) { for (Number num : list) { System.out.println(num); } }
public static void main(String[] args) { List<Integer> intList = Arrays.asList(1, 2, 3); List<Double> doubleList = Arrays.asList(1.1, 2.2, 3.3);
printNumbers(intList); printNumbers(doubleList); } }
|
(2) 下界通配符: <? super T>
- 适用于写入数据。
- 表示类型必须是
T
或 T
的父类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import java.util.*;
public class Main { public static void addNumbers(List<? super Integer> list) { list.add(100); list.add(200); System.out.println(list); }
public static void main(String[] args) { List<Number> numberList = new ArrayList<>(); addNumbers(numberList); } }
|
✅ 5. 泛型中的通配符 <?>
<?>
表示未知类型,称为通配符。
- 常用于方法参数中,表示可以接受任何类型的集合。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import java.util.*;
public class Main { public static void printList(List<?> list) { for (Object obj : list) { System.out.println(obj); } }
public static void main(String[] args) { List<String> strList = Arrays.asList("Java", "Python"); List<Integer> intList = Arrays.asList(1, 2, 3);
printList(strList); printList(intList); } }
|
✅ 6. 泛型的限制
基本数据类型不能作为泛型类型
1
| List<int> list = new ArrayList<>();
|
解决方法: 使用包装类 Integer
替代 int
:
1
| List<Integer> list = new ArrayList<>();
|
不能创建泛型数组
解决方法: 使用 Object
数组并强制转换:
1 2
| @SuppressWarnings("unchecked") T[] array = (T[]) new Object[10];
|
✅ 总结
- 泛型类:使用
<T>
声明通用类型,使类可以操作不同的数据类型。
- 泛型方法:在方法中使用
<T>
使其支持不同类型的参数。
- 通配符
<?>
:表示未知类型,用于通用代码。
- 上界
<? extends T>
:用于读取数据。
- 下界
<? super T>
:用于写入数据。