9.2 深入泛型 9.2.1 定义泛型接口 泛型类
9.2 深入泛型
所谓泛型,就是允许在定义类、接口、方法时使用类型形参,这个类型形参(或叫泛型)将在声明变量、创建对象、调用方法时动态地指定(即传入实际的类型参数,也可称为类型实参)。
Java5
改写了集合框架中的全部接口和类,为这些接口、类增加了泛型支持,从而可以在声明集合变量、创建集合对象时传入类型实参,这就是在前面程序中看到的List<String>
和ArrayList<String>
两种类型。
9.2.1 定义泛型接口、类
下面是Java5
改写后List
接口、 Iterator
接口、Map
的代码片段。
1 | ...... |
1 | ...... |
1 | ...... |
上面三个接口声明是比较简单的,除了尖括号中的内容—这就是泛型的实质:
允许在定义接口、类时声明泛型形参
,泛型形参
在整个接口、类体内可当成类型使用,几乎所有可使用普通类型的地方都可以使用这种泛型形参。
除此之外,1、2处方法声明返回值类型是Iterator<E>
、Set<K>
,这表明Set<K>
形式是一种特殊的数据类型,是一种与Set
不同的数据类型:可以认为Set<K>
是Set
类型的子类。
例如使用List
类型时,如果为E
形参传入String
类型实参,则产生了一个新的类型: List<String>
类型,可以把List<String>
想象成E
被全部替换成String
的特殊List
子接口。
1 | //List<string>等同于如下接口 |
通过这种方式,就解决了9.1.2节中的问题,虽然程序只定义了一个List<E>
接口,但实际使用时可以产生无数多个List
接口,只要为E传入不同的类型实参,系统就会多出一个新的List
子接口。不过必须指出:List<String>
绝不会被替换成ListString
,系统没有进行源代码复制,二进制代码中没有,磁盘中没有,内存中也没有。
包含泛型声明的类型可以在定义变量、创建对象时传入一个类型实参,从而可以动态地生成无数多个逻辑上
的子类,但这种子类在物理上并不存在。
任何类和接口都可以加上泛型声明
可以为任何类、接口增加泛型声明(并不是只有集合类才可以使用泛型声明,虽然集合类是泛型的重要使用场所)。
程序示例
下面自定义一个Apple
类,这个Apple
类就可以包含一个泛型声明:
1 | // 定义Apple类时使用了泛型声明 |
上面程序定义了一个带泛型声明的Apple<T>
类(不要理会这个泛型形参是否具有实际意义),使用Apple<T>
类时就可为T形参传入实际类型,这样就可以生成如Apple<String>
、 Apple<double>
…形式的多个逻辑子类(物理上并不存在)。这就是9节可以使用List<String>
、 ArrayList<String>
等类型的原因—JDK
在定义List
、 Array List
等接口、类时使用了泛型声明,所以在使用这些类时为之传入了实际的类型参数。
泛型的构造器还是和类名相同
当创建带泛型声明的自定义类,为该类定义构造器时,构造器名还是原来的类名,不要增加泛型声明。例如,为Apple<T>
类定义构造器,其构造器名依然是Apple
,而不是Apple<T>
!调用该构造器时却可以使用Apple<T>
的形式,当然应该为T形参传入实际的类型参数。
Java7
提供了菱形语法,允许省略<>
中的类型实参。