什么是泛型?为什么使用泛型?
泛型,就是参数化类型。提到参数,最熟悉的就是定义方法时候的形参,然后调用此方法时传递实参。顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义为参数形式(可以称之为类型参数),然后在使用/调用时传入具体的类型(类型实参)。
泛型的本质是为了参数化类型(再不创建新的类型的情况下,通过泛型指定的不同的类型来控制形参具体限制的类型)。也就是说在泛型使用过程中,操作的数据类型被指定为一个参数,这种参数可以用在类、接口和方法中,分别称之为泛型类、泛型接口和泛型方法。
泛型的特性:
泛型只在编译阶段有效,在编译之后程序会采取去泛型化的措施,也就是说Java中的泛型只在编译阶段有效,在编译过程中,正确检验泛型结果后会将泛型的相关信息擦除,并且在对象进入和离开方法的边界处添加类型检验和类型转换的方法,也就是说类型信息不会进入到运行阶段。
泛型的使用:
泛型的使用有三种方式:泛型类、泛型接口、泛型方法
一、泛型类:
泛型类型用于类的定义中,被称为泛型类。通过泛型可以完成对一组类的操作对外开放的是相同的接口。
具体的应用实例:
特别说明:定义的泛型类,并不一定要传入泛型类型实参。在使用泛型的时候如果传入的是泛型实参,则会根据传入的泛型实参作相应的限制,此时泛型才会起到本应起到的限制作用;如果不传入泛型类型实参的话,在泛型类中使用泛型的方法或者成员变量定义的类型可以是任何类型;泛型的类型参数只能是类类型,不能是简单类型。不能对确切的泛型类型使用instanceOf操作,否则编译器会报错。
二、泛型接口:
泛型接口与泛型类的定义以及使用基本是相同的,泛型接口常被用在各种类的生产器中。
1、泛型接口的基本用法(定义一个泛型接口):
2、当实现泛型接口的类,未传入泛型实参时:
当实现泛型接口的类没有传入泛型实参的情况时,与泛型类的定义相同,在声明类时需要将泛型的声明也一起加到类中。即:class FruitGenerator<T> implements Generator<T>{};
3、当实现泛型接口的类传入泛型实参的时候:
相当于定义了一个生产器实现这个接口,虽然我们只创建了一个泛型接口,但是因为泛型接口中参数类型是不确定的,所以可以形成无数种类型的Generator接口。在实现泛型接口的实现类中,如果传入了泛型实参,那么在这个类中所有使用该泛型类型的地方都要替换成成传入的实参类型。
注意:同一种泛型可以对应多个版本(因为参数类型是不确定的),但是不同的泛型参数的泛型实例之间是不兼容的。
4、泛型方法
泛型类实在实例化类的时候指明泛型的具体类型;泛型方法实在调用方法的时候指明泛型的具体类型。
说明:
- public和返回值 之间的<T>非常重要,可以理解为声明此方法为泛型方法。
- 只有声明了<T>的方法才是泛型方法,泛型类中的使用了泛型的成员方法并不是泛型方法。
- <T>表明该方法将使用泛型类型T,此时才可以在方法中使用泛型类型T。
- 与泛型类的定义一样,T只是一个标识符,可以随便写。
4.1、泛型方法的基本用法
泛型方法中一个比较特殊的情况就是泛型方法出现在泛型类中
注意:class GenerateTest<T>
这是一个泛型类,那么在里边包含的三个方法其中
show_1只是一个普通的方法,只是这个方法存在于泛型类里边,
但它所包含的参数T是和泛型类中的T一致的;show_3,show_2这两个方法是泛型类里的泛型方法,他们所含的泛型方法是一个全新的类型,可以和泛型类中声明的T一样,也可以 不一样。
泛型方法的总结:泛型方法能使方法独立于类而产生变化,一个基本的原则就是:无论何时,就应该尽量使用泛型方法 。
5、泛型边界
Ø 为泛型添加上边界,即是传入的类型实参必须是指定类型的子类型
Ø 在泛型方法中添加上下边界限制的时候,必须在权限说明与返回值之间的<T>之间添加上下边界,即是在泛型声明的时候添加。泛型的上下边界添加,必须与泛型的声明在一起
6、关于泛型数组
不能创建一个确切的泛型类型的数组,而使用通配符创建泛型数组是可以的。