【Java】泛型(Generic)
1 概述
1.1 为什么要有泛型
Java 中的泛型是在 JDK 1.5 中引入的一个新特性,其作用是参数化类型(parameterized type)。由于经常会遇到在集合容器类中存放对象或取出对象,并根据需要转型为相应的对象的情形。而集合容器类在设计声明时不能确定这个容器到底实际存的是什么类型的对象,所以在 JDK 1.5 之前没有引入泛型时,如果要实现对不同引用类型的变量进行操作,只能通过 Object 类来实现参数类型的抽象化,JDK 1.5 之后使用泛型来解决,使用泛型可以在存取对象时明确地指出对象的类型。这个时候除了元素的类型不确定,其他的部分是确定的,例如关于这个元素如何保存,如何管理等是确定的,因此此时把元素的类型设计成一个参数,这个类型参数叫做泛型。
如:Collection,List,ArrayList 这个 就是类型参数,即泛型。
1.2 泛型的概念
所谓泛型,就是允许在定义类、接口时通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型。这个类型参数将在使用时(例如,继承或实现这个接口,用这个类型声明变量、创建对象时)确定(即传入实际的类型参数,也称为类型实参),目的在于定义安全的泛型类。
从 JDK 1.5 以后,Java 引入了“参数化类型(parameterized type)”的概念,允许我们在创建集合时再指定集合元素的类型,正如:List,这表明该 List 只能保存字符串类型的对象。JDK 1.5 改写了集合框架中的全部接口和类,为这些接口、类增加了泛型支持,从而可以在声明集合变量、创建集合对象时传入类型实参。
1.3 泛型和直接使用 Object 类的区别
- Object 类的范围很大,Object 是所有类的父类,所以任何类型都可以添加到集合中,这就会导致类型不安全。
- 使用 Object 类型的对象,从集合中读取对象需要强转类型,这就使过程繁琐,且可能出现 ClassCastException 异常。
在集合中没有泛型时:
在集合中有泛型时:
2 在集合中使用泛型
-
集合接口或集合在 JDK 1.5 时都修改为带泛型的结构。
-
在实例化集合类时,可以指明具体的泛型类型。
-
指明完以后,在集合类或接口中凡是定义类或接口时,内部结构使用到类的泛型的位置,都指定为实例化的泛型类型。
比如:add(E e) → 实例化以后:add(Integer e)
-
泛型的类型必须是类,不能是基本数据类型。需要用到基本数据类型时,使用包装类替换。(注意)
-
如果实例化时,没有指明泛型的类型。默认类型为 java.lang.Object 类型。
public class GenericTest {
// 在集合中使用泛型之前的情况:
@Test
public void test1() {
ArrayList list = new ArrayList();
// 需求:存放学生的成绩
list.add(78);
list.add(76);
list.add(89);
list.add(88);
// 问题一:类型不安全,容易混进来非成绩类型的数据
list.add("Tom");
for(Object score : list) {
// 问题二:强转时,可能出现 ClassCastException
int stuScore = (Integer) score;
System.out.println(stuScore); // 只有删除 List 中的 "Tom" 才能解决 ClassCastException
}
}
// 在集合中使用泛型的情况:以 ArrayList 为例
@Test
public void test2() {
ArrayList<Integer> list = new ArrayList<>();
list.add(78);
list.add(87);
list.add(99);
list.add(65);
// 编译时,就会进行类型检查,保证数据的安全
// list.add("Tom");
// 方式一
for (Integer score : list) {
// 避免了强转操作
int stuScore = score;
System.out.println(stuScore);
}
// 方式二
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()) {
int stuScore = iterator.next();
System.out.println(stuScore);
}
}
// 在集合中使用泛型的情况:以 HashMap 为例
@Test
public void test3() {
// HashMap<String, Integer> map = new HashMap<String, Integer>();
// JDK 7 新特性:类型推断
HashMap<String, Integer> map = new HashMap<>();
map.put("Tom", 87);
map.put("Jerry", 87);
map.put("Jack", 87);
// map.put(123, "ABC");
// 泛型的嵌套
Set<Map.Entry<String, Integer>> entry = map.entrySet();