什么是泛型
约 740 字大约 2 分钟
2025-07-17
1.1 泛型的引入
在 Java 标准库中,ArrayList 是一种可以动态调整大小的数组,它内部基于 Object[] 数组实现。
public class ArrayList {
private Object[] array;
private int size;
public void add(Object e) {...}
public void remove(int index) {...}
public Object get(int index) {...}
}如果使用上述 ArrayList 存储 String 类型的数据,会存在以下缺点:
- 需要强制类型转换;
- 容易出错,例如,可能会出现
ClassCastException异常。
例如,从 ArrayList 中获取 String 类型的数据时,需要进行强制类型转换:
ArrayList list = new ArrayList();
list.add("Hello");
// 获取到Object,必须强制转型为String:
String first = (String) list.get(0);为了解决这个问题,可以为每种类型单独编写一个 ArrayList,例如 StringArrayList、IntegerArrayList 等。但是,这种方式会导致大量的重复代码,且无法应对所有可能的类型。
1.2 泛型的定义
为了解决上述问题,Java 引入了泛型的概念。泛型允许定义一种模板,例如 ArrayList<T>,其中 T 可以是任何 class。
public class ArrayList<T> {
private T[] array;
private int size;
public void add(T e) {...}
public void remove(int index) {...}
public T get(int index) {...}
}通过泛型,可以创建任意类型的 ArrayList:
// 创建可以存储String的ArrayList:
ArrayList<String> strList = new ArrayList<String>();
// 创建可以存储Float的ArrayList:
ArrayList<Float> floatList = new ArrayList<Float>();
// 创建可以存储Person的ArrayList:
ArrayList<Person> personList = new ArrayList<Person>();这样,既实现了代码的复用,又通过编译器保证了类型安全。
1.3 泛型的类型检查
编译器会对泛型类型进行检查,确保类型安全。
ArrayList<String> strList = new ArrayList<String>();
strList.add("hello"); // OK
String s = strList.get(0); // OK
strList.add(new Integer(123)); // compile error!
Integer n = strList.get(0); // compile error!1.4 向上转型
在 Java 标准库中,ArrayList<T> 实现了 List<T> 接口,因此,类型 ArrayList<T> 可以向上转型为 List<T>。
public class ArrayList<T> implements List<T> {
...
}
List<String> list = new ArrayList<String>();需要特别注意的是,不能把 ArrayList<Integer> 向上转型为 ArrayList<Number> 或 List<Number>。
这是因为如果允许这种转型,可能会导致类型安全问题。例如,可以将一个 Float 对象添加到 ArrayList<Number> 中,而 ArrayList<Integer> 实际上只能存储 Integer 对象,这会导致 ClassCastException 异常。
// 创建ArrayList<Integer>类型:
ArrayList<Integer> integerList = new ArrayList<Integer>();
// 添加一个Integer:
integerList.add(new Integer(123));
// “向上转型”为ArrayList<Number>:
ArrayList<Number> numberList = integerList;
// 添加一个Float,因为Float也是Number:
numberList.add(new Float(12.34));
// 从ArrayList<Integer>获取索引为1的元素(即添加的Float):
Integer n = integerList.get(1); // ClassCastException!因此,编译器为了避免这种错误,根本就不允许把 ArrayList<Integer> 转型为 ArrayList<Number>。
注
ArrayList<Integer> 和 ArrayList<Number> 两者完全没有继承关系。
泛型的继承关系可以用下图表示:当 T 不变时,可以向上转型;T 本身不能向上转型。
List<Integer> ArrayList<Number>
▲ ▲
│ │
│ X
│ │
ArrayList<Integer> ArrayList<Integer>