文章目录
- 一、概述
- 1、什么是泛型
- 2、用泛型最直接的优点
- 3、分类
- 二、泛型详解
- 1、泛型类
- (1)概述
- (2)代码实例
- 2、泛型派生类
- (1)概述
- (2)代码实例
- (3)扩展:泛型接口
- 3、泛型方法
- (1)概述
- (2)代码实例
- (3)可变参数的泛型方法
- 4、泛型通配符
- (1)什么是泛型通配符
- (2)代码实例
- (3)上边界
- (4)下边界
- 5、泛型擦除
- (1)什么是泛型擦除
- (2)代码实例
- 6、如何创建泛型数组
- (1)方案一:使用反射
- (2)方案二:参考ArrayList存储Object数组
一、概述
1、什么是泛型
是在定义类、接口和方法时,可以在声明时通过一定的格式指定其参数类型。
使用时再指定具体的类型,从而使得类、接口和方法可以被多种类型的数据所实例化或调用。
这种可以在编译时进行参数类型检查
的技术被称为泛型,是JDK5中引入的一个新特性。
本质是参数化类型
给类型指定一个参数,在使用时再指定此参数具体的值,那这个类型就可以在使用时决定
。
优点:把运行时的错误,提前到编译时,这样就可以在编译时把错误提示出来,避免了运行时出现错误;使用泛型可以提高代码的复用性,因为它可以支持多种类型的数据。
2、用泛型最直接的优点
在没有泛型之前,从集合中读取到的每一个对象都必须进行类型转换。
如果插入了错误的类型对象,在运行时的转换处理就会出错。
集合容器里面如果没指定类型,默认都是Object类型,那什么到可以插入。
减少了源代码中的强制类型转换,代码更加可读。
3、分类
可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法
。
泛型字母通常类型参数都使用大写的单个字母:
T:任意类型 type
E:集合中元素的类型 element
K:key-value形式 key
V:key-value形式 value
二、泛型详解
1、泛型类
(1)概述
泛型类必须是引用类型,即类类型(不能使用基本数据类型)
。
在类名后添加一对尖括号,并在尖括号中填写类型参数。
如果参数可以有多个,多个参数使用逗号分隔。
注意:
泛型类创建的使用没有指定类型,则默认是object类型。
泛型类型从逻辑上看是多个类型,实际都是相同类型。Java 可以创建对应的泛型对象和泛型数组引用,但不能直接创建泛型对象和泛型数组
。
Java 有类型擦除,任何泛型类型在擦除之后就变成了 Object 类型,因此创建泛型对象就相当于创建了一个 Object 类型的对象,所以直接创建泛型对象和泛型数组也的行为被编译器禁止。泛型类中使用了泛型的方法,不能定义为static!
(2)代码实例
2、泛型派生类
(1)概述
如果泛型类的子类也是泛型类,那父类和子类的类型要一致。
如果子类泛型有多个,那需要包括父类的泛型类型。
(2)代码实例
(3)扩展:泛型接口
规则和泛型类一样
。
如果实现类是泛型类,那接口和实现类的泛型类型要一致;如果实现类泛型有多个,那需要包括接口的泛型类型。
如果实现类不是泛型类,那接口要明确泛型类的类型。
3、泛型方法
(1)概述
调用方法的时候指定泛型的具体类型。
注意,修饰符和返回值中间有<T, E...>才是泛型方法
,泛型类里面的普通返回值类型不是泛型方法。
泛型类的类型和泛型方法的类型是互相独立的,同名也不影响,同名的话泛型方法上的泛型优先。
声明了【泛型方法】在参数列表和方法体
里面才可以用对应的泛型。
泛型方法可以定义为静态方法
。
(2)代码实例
(3)可变参数的泛型方法
我们可以看出,可变参数是不限制参数的类型的。
4、泛型通配符
(1)什么是泛型通配符
Java泛型的通配符是用于解决泛型之间引用传递间的特殊语法。
通用类型通配符 <?>,如List<?>
:
主要作用就是让泛型能够接受未知类型的数据。
可以把?
看成所有泛型类型的父类,是一种真实的类型,类型通配符是实参,不是形参。
固定上边界的通配符 采用<? extends E>
的形式:
使用固定上边界的通配符的泛型,只能够接受指定类及其子类类型的数据。
采用<? extends E>
的形式,这里的E就是该泛型的上边界。
注意:这里虽然用的是extends关键字,却不仅限于继承了父类E的子类,也可以代指显现了接口E的类。
固定下边界的通配符,采用<? super E>
的形式:
使用固定下边界的通配符的泛型,只能够接受指定类及其父类类型的数据。
采用<? super E>
的形式,这里的E就是该泛型的下边界。
可以为一个泛型指定上边界或下边界,但是不能同时指定上下边界。
(2)代码实例
(3)上边界
固定上边界的通配符 采用<? extends E>
的形式。
使用固定上边界的通配符的泛型,只能够接受指定类及其子类类型的数据
。
采用<? extends E>
的形式,这里的E就是该泛型的上边界。
注意:这里虽然用的是extends关键字,却不仅限于继承了父类E的子类,也可以代指显现了接口E的类。
(4)下边界
固定下边界的通配符,采用<? super E>
的形式。
使用固定下边界的通配符的泛型,只能够接受指定类及其父类类型的数据
。
采用<? super E>
的形式,这里的E就是该泛型的下边界。
可以为一个泛型指定上边界或下边界,但是不能同时指定上下边界。
5、泛型擦除
(1)什么是泛型擦除
泛型是jdk1.5后出现的,但泛型代码和常规版本代码可以兼容,主要原因是泛型信息是在代码编译阶段。代码编译完成后进入JVM运行前,相关的泛型类型信息会被删除,这个即泛型类型擦除
。
作用范围:类泛型,接口泛型,方法泛型。
(2)代码实例
无限制类型擦除,擦除后都是Object
类型。
有限制类型擦除,擦除后就是指定的父类。
6、如何创建泛型数组
背景:
在Java 中是不能直接创建泛型对象和泛型数组的。
主要原因是Java 有类型擦除,任何泛型类型在擦除之后就变成了 Object 类型或者对应的上限类型。
那定义的类中如果需要用到泛型数组,如何解决这个问题?
需求:创建一个类里面支持泛型数组和返回全部数组的方法。
(1)方案一:使用反射
(2)方案二:参考ArrayList存储Object数组
获取数组的时候,无法进行强转,会报错。
ArrayList会最终有个toArray的方法: