概要
泛型在Java中有很重要的地位,在面向对象编程及各种设计模式中有非常广泛的应用。
泛型的定义
泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参,而顾名思义,参数化类型就是将类型原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。
为什么使用泛型
泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制具体限制的类型)。也就是说在泛型使用过程中,操作的数据类型被指定为一个参数,这种参数可以作用于类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。
类型擦除
Java中的泛型基本上都是在编译器这个层次来实现的,在生成的Java字节码中是不包含泛型中的类型信息的。使用泛型的时候加上的类型参数,会被编译器在编译的时候去掉,这个过程就称为类型擦除。如在代码中出现的List
很多泛型的奇怪特性都与这个类型才擦除的存在有关,包括:
- 泛型类并没有自己独有的Class类对象。比如不存在List
.class,而只有List.class - 静态变量是被泛型类的所有实例所共享的。对于声明为AClass
的类,访问其中的静态变量定位方法仍然是AClass.staticFun()。不管是通过AClass 还是AClass 创建的对象,都是共享一个静态变量 - 泛型的类型参数不能用在Java异常处理的catch语句中。因为异常处理是由JVM在运行时刻来进行的。由于类型信息被擦除,JVM是无法区分两个异常类型MyExpection
和MyExpection 的。对于JVM来说,它们都是MyExpection类型的,也就无法执行与异常对应的catch语句。
类型擦除的基本过程也比较简单,首先是找到用来替换类型参数的具体类。这个具体类一般是Object,如果指定了类型参数的上界,则使用这个上界。把代码中的类型参数都替换成具体的类。同时去掉出现的类型声明,即去掉<>的内容。比如T get()方法声明就变成Object get(),List
|
|
当类型信息被擦除之后,上述类的声明变成了class MyString implements Comparable。但是这样的话,类MyString就会有编译错误,因为没有实现接口Comparable声明的int compareTo(Object) 方法。这个时候就由编译器来动态生成这个方法。
通配符
在使用泛型类的时候,既可以指定一个具体的类型,如List