一、泛型概述

  • 泛型:JDK1.5设计了泛型的概念,泛型即为“类型参数”,这个类型参数在声明它的类、接口或方法中,代表未知的通用的类型

  • 泛型的优点:避免类型转换,通过编译提示异常来保证安全

  • 泛型语法:<类型>

    • 一般形式为,这里可以看做类型形参,等看做类型实参
  • 泛型之后的Java数据类型

    • Class:Class类的实例表示正在运行的 Java 应用程序中的类和接口
      • GenericArrayType:泛化的数组类型,即T[]
      • ParameterizedType:参数化类型(例如:Comparator,Comparator
      • TypeVariable:类型变量(例如:Comparator中的T,Map<K,V>中的K,V)
      • WildcardType:通配符类型(例如:Comparator<?>)

二、泛型类与泛型接口

  • 语法格式:class 类名/接口名 <类型变量列表>

  • 核心类库中的泛型类/接口

    • 集合框架内的相关类和接口
    • Comparator接口
    • Comparable接口
  • 自定义泛型类/接口

    • 使用场景:
      • 当某个类/接口的非静态变量的类型不确定,需要在创建对象或子类继承时才能确定
      • 当某个(些)类/接口的非静态方法的形参类型不确定,需要在创建对象或子类继承时才能确定
    • <类型变量列表>可以是一个或多个类型变量,一般都是使用单个的大写字母表示
  • 泛型类/接口的使用:需要在创建泛型类的对象时指定类型变量对应的实际类型参数

    • 实际类型参数必须是引用数据类型,不能是基本数据类型
    • 子类/接口继承泛型父类/接口、或实现类实现泛型父接口时
      • 父类/接口指定类型变量对应的实际类型参数,此时子类或实现类不再是泛型类
      • 父类/接口指定类型变量(该类型变量可以和原来字母一样,也可以换一个字母),此时子类、子接口、实现类仍然是泛型类或泛型接口
    • 泛型不存在多态现象,指定泛型实参时,必须左右两边一致
    • <类型变量列表>中的类型变量不能用于类的静态成员

JDK1.7支持简写形式:Student stu1 = new Student<>();

三、泛型方法

  • 语法格式:【修饰符】 <类型变量列表> 返回值类型 方法名(【形参列表】)【throws 异常列表】{}

  • 核心类库中的泛型方法

    • java.util.Arrays数组工具类的大多数方法
  • 自定义泛型方法

    • 使用场景:
      • 定义类、接口时没有使用<类型变量>,但是某个方法形参类型不确定
      • 当某个静态方法的形参类型不确定时,静态方法可以单独定义<类型变量>
    • <类型变量列表>:可以是一个或多个类型变量,一般都是使用单个的大写字母表示
  • 泛型方法的使用:方法调用时,实参的类型确定泛型方法类型变量的具体类型

四、类型变量的上限

  • 语法格式:

    • 单个上限:<类型变量 extends 上限>
    • 多个上限:<类型变量 extends 上限1 & 上限2>(只能有一个类,且必须写在最左边)
  • 如果在声明<类型变量>时没有指定任何上限,默认上限是java.lang.Object

五、泛型的擦除

  • 泛型擦除:当使用参数化类型的类/接口或方法时,没有指定泛型,则自动按照最左边的第一个上限处理(如果没有指定上限,上限为Object)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package com.atguigu.wildcard;

import java.util.ArrayList;
import java.util.Collection;

public class TestProblem {
public static void m1(Collection<Object> coll){
for (Object o : coll) {
System.out.println(o);
}
}
public static void m2(Collection coll){
for (Object o : coll) {
System.out.println(o);
}
}
public static <T> void m3(Collection<T> coll){
for (T o : coll) {
System.out.println(o);
}
}

public static void main(String[] args) {
m1(new ArrayList<Object>());//Collection<Object> coll = new ArrayList<Object>();
m1(new ArrayList<>());//Collection<Object> coll = new ArrayList<>();//与上面完全等价
m1(new ArrayList());//Collection<Object> coll = new ArrayList();//有警告
// m1(new ArrayList<String>());//Collection<Object> coll = new ArrayList<String>();//错误

//编译看左边,左边泛型擦除,此处泛型按照Object处理,右边泛型指定啥都没用
m2(new ArrayList<Object>());//Collection coll = new ArrayList<Object>();
m2(new ArrayList<>());//Collection coll = new ArrayList<>();//与上面完全等价
m2(new ArrayList());//Collection coll = new ArrayList();//泛型擦除
m2(new ArrayList<String>());//Collection coll = new ArrayList<String>();

m3(new ArrayList<Object>());//Collection<Object> coll = new ArrayList<Object>();
m3(new ArrayList<>());//Collection<> coll = new ArrayList<>();//与上面完全等价
m3(new ArrayList());//Collection<Object> coll = new ArrayList();//有警告
m3(new ArrayList<String>());//Collection<String> coll = new ArrayList<String>();
}
}

六、类型通配符

  • 使用场景:声明一个泛型类/接口的变量/形参,但仍然无法确定这个泛型类/接口的类型变量的具体类型

  • 类型通配符的三种使用形式

    • <?>:代表任意类型
    • <? extends 上限>:代表<=上限的类型
    • <? super 下限>:代表>=下限的类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.atguigu.wildcard;

import java.util.ArrayList;
import java.util.Collection;

public class TestWildcard {
public static void m4(Collection<?> coll){
for (Object o : coll) {
System.out.println(o);
}
}

public static void main(String[] args) {
//右边泛型指定为任意类型或不指定都可以
m4(new ArrayList<Object>());//Collection<?> coll = new ArrayList<Object>();
m4(new ArrayList<>());//Collection<?> coll = new ArrayList<>();
m4(new ArrayList());//Collection<?> coll = new ArrayList();
m4(new ArrayList<String>());//Collection<?> coll = new ArrayList<String>();
}
}