泛型(generic)是指参数化类型的能力。可以定义带泛型类型的类或方法,随后编译器会用具体的类型来替换它(泛型实例化)。使用泛型的主要优点是能够在编译时,而不是在运行时检测出错误。(泛型类型必须是引用类型。)
一、泛型类和泛型接口
注意:
- 创建一个字符串堆栈可以使用new GenericStack< String >(),这可能会让我们误认为构造方法应该被定义为public GenericStack< E >(),这是错误的,正确的应该是public GenericStack()。
- 有时候,泛型类可能会有多个参数。在这种情况下,应将所有参数一起放在尖括号中,并用逗号分隔开,如< E1, E2, E3 >
- 可以定义一个类或一个接口作为泛型或者接口的子类型。例如,Java API中的public class String implementes Comparable< String >
二、泛型方法
- 为了定义一个类为泛型类型,需要将泛型类型放到类名之后,例如GenericStack< E >,为了定义一个方法为泛型类型,需要将泛型放到方法返回值之前,例如< E > void max(E o1, Eo2)。
- 可以将泛型指定为另外一种类型的子类型,这样的泛型称为受限的(bounded)。例如< E extends GeometricObject >,特殊的非受限泛型类型< E >和< E extends Object >是一样的。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
三、通配泛型
尽管Integer是Number的子类型,但是GenericStack< Integer >不是GenericStack< Number >的子类型。为了解决这个问题,可以使用通配泛型(GenericStack< ? extends Number >)。通配泛型有三种形式:?、? extends T、? super T,其中T是某个泛型类型。第一种形式 ? 称为非受限通配,它和 ? extends Object 是一样的;第二种形式 ? extends T 称为受限通配,标示T或T的一个未知子类型;第三种形式 ? super T 称为受限通配,标示T或T的一个未知父类型。
四、泛型消除
泛型是使用一种称为类型消除(type erasure)的方法实现的。编译器使用泛型类型信息编译代码,但是随后会消除它。因此,泛型信息在运行时是不可用的,这种方法可以使泛型代码向后兼容使用原始类型的遗留代码。
五、泛型限制
- 不能使用泛型参数创建实例,即不能使用new E()
- 不能使用泛型参数创建数组,即不能使用new E[]
- 异常类不能是泛型的,因为泛型类不能扩展java.lang.Throwable。
- 在静态环境下不允许类的参数是泛型类型。由于泛型类的所有实例都有相同的运行时类,所以泛型类的静态变量和方法是被它的所有实例所共享的。因此,在静态方法、数据域或者初始化语句中,为了类而引用泛型类型参数是非法的。例如:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10