JavaSE 泛型
Posted ITWEL
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaSE 泛型相关的知识,希望对你有一定的参考价值。
一.泛型(What)
(一)基本介绍
泛型就是允许在定义类、接口时通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型。
Java泛型(generics)是JDK5中引入的一个新特性,泛型提供了编译类型安全监测机制,该机制允许在编译时检测到非法的类型。
(二)本质
泛型的本质是“参数化类型”,即给类型制定一个参数,然后在使用时在指定此参数的值,那样这个类型就可以在使用时决定了。这种参数类型可以在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。
核心思想:将一个集合中的内容限制为一个特定的数据类型。
二.为何使用泛型?(Why)
(一)保证类型的安全性
在没有泛型前,从集合中读取到的每一个对象都必须进行类型转换,如果插入了错误的类型对象,在运行时候就会出错。
有了泛型之后,定义好的集合在编译时如果遇到了不匹配类型数据就会出现编译错误,使得程序更加安全,增强了程序的健壮性。
(二)消除强制转换
消除了源码中许多强制类型转换,增强了代码的可读性并且减少了出错次数。
(三)避免拆箱、装箱操作
在非泛型编程中,将简单类型作为Object传递时会引起Boxing(装箱)和
Unboxing(拆箱)操作,开销均是比较大的。泛型变量固定了类型,使用的时候就已经知道是值类型还是引用类型,避免了不必要的装箱和拆箱操作。
(四)提高了代码的重用性
三.如何应用泛型呢?(How)
使用方式:泛型类、泛型接口、泛型方法
补充:还可以应用在集合中
(一)集合
引用于集合中,添加指定类型的数据,如果添加类型错误,编译会出现错误。
说明:
①集合接口或集合类在jdk5.0时都修改为带泛型的结构
②在实例化集合类时,可以指明具体的泛型类型
③如果实例化时候,没有指明泛型的类型,默认的类型为java.lang.Object类型
单列集合:
双列集合:
(二)泛型类(接口)
描述:在类(或接口)的定义是加入泛型
格式:
public class(或 interface) 类名(或接口名)<泛型类型1 ....>
说明:
①泛型类型必须是引用类型(非基本数据类型)
②尖括号中的类型参数可以为一个或多个
规范(大写字母)
T:任意类型 type
E:集合中元素的类型 element
K:key-value形式 key
V: key-value形式 value
使用:
注意:
(1)static 的方法不能声明泛型(不能传入或使用泛型变量)
(2)不能在try---catch中使用泛型
自然排序
定制排序
拓展:泛型在继承中的应用
(三)泛型方法
理解:在方法中出现了泛型的结构,泛型参数与类的泛型参数没有任何关系
格式:
[访问权限] <泛型> 返回类型 方法名([泛型标识 参数名称]) 抛出的异常
具体使用
测试
说明:
①非泛型类中也是可以声明泛型方法的
②泛型方法可以声明为static的(泛型参数是在调用是)
泛型在继承方面的体现:
(1)类A是类B的父类,但是G<A>和G<B>二者不具备子父类关系,二者是并列关系
(2)类A是类B的父类,A<G> 是 B<G>的父类
通配符的使用
分类:
(1)无边界的通配符(Unbounded Wildcards),
采用 <?> 的形式,比如 List<?>,无边界的通配符的主要作用就是让泛型能够接受未知类型的数据。
(2)固定上边界的通配符(Upper Bounded Wildcards)
使用固定上边界的通配符的泛型,就能够接受指定类及其子类类型的数据。要声明使用该类通配符,采用 <? extends E> 的形式,这里的 E 就是该泛型的上边界。
注意:这里虽然用的是 extends 关键字,却不仅限于继承了父类 E 的子类,也可以代指实现了接口 E 的类。
(3)固定下边界的通配符(Lower Bounded Wildcards)
使用固定下边界的通配符的泛型,就能够接受指定类及其父类类型的数据。要声明使用该类通配符,采用 <? super E> 的形式,这里的 E 就是该泛型的下边界。
具体使用:
场景一:
说明:
(1)添加:对于List<?>不能向其中添加元素(null除外)
(2)获取:允许读取数据,读取的数据类型为Object
场景二:
说明:
(1)? extends A:
G<? extends A>可以作为G<A>和G<B>的父类的,其中B是A的子类
(2)? super A:
G<? super A>可以作为G<A>和G<B>的父类的,其中B是A的父类
(3)在进行添加时一定要注意子父类之间的关系
总结
(1)泛型类可能有多个参数,此时应将多个参数一起放在尖括号内。比如: <E1,E2,E3>
(2)泛型类的构造器如下:public GenericClass()。
错误写法:public GenericClass<E>()
(3)实例化后,操作原来泛型位置的结构必须与指定的泛型类型一致。
(4)泛型不同的引用不能相互赋值。
尽管在编译时ArrayList和ArrayList是两种类型,但是,在运行时只有 一个ArrayList被加载到JVM中。
(5)泛型如果不指定,将被擦除,泛型对应的类型均按照Object处理,但不等价 于Object。
感悟:如果要是使用泛型就一直用
(6)如果泛型结构是一个接口或抽象类,则不可创建泛型类的对象。
(7)jdk1.7,泛型的简化操作:ArrayList flist = new ArrayList<>();
(8)泛型的指定中不能使用基本数据类型,可以使用包装类替
(9) 在类/接口上声明的泛型,在本类或本接口中即代表某种类型,可以作为非静态属性的类型、 非静态方法的参数类型、非静态方法的返回值类型。但在静态方法 中不能使用类的泛型。
(10) 异常类不能是泛型的
(11) 不能使用new E[]。但是可以:E[] elements = (E[])new Object[capacity]; 参考:ArrayList源码中声明:Object[] elementData,而非泛型参数类型数组。
(12)父类有泛型,子类可以选择保留泛型也可以选择指定泛型类型:
子类不保留父类的泛型:按需实现
没有类型 擦除
具体类型
子类保留父类的泛型:泛型子类
全部保留
部分保留
实例如下:
如有不足之处,欢迎读者在评论区留言,非常感谢
以上是关于JavaSE 泛型的主要内容,如果未能解决你的问题,请参考以下文章