概述
泛型在java中有很重要的地位,在面向对象编程及各种设计模式中有非常广泛的应用。
什么是泛型?
泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。
泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。也就是说在泛型使用过程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。
为什么要使用泛型?
Java语言引入泛型的好处是安全简单。可以将运行时错误提前到编译时错误。在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。
泛型的特性
泛型类型在逻辑上看以看成是多个不同的类型,实际上都是相同的基本类型。
|
|
泛型通配符
我们知道Ingeter是Number的一个子类,上述代码也验证过Generic<Ingeter>
与Generic<Number>
实际上是相同的一种基本类型。那么问题来了,在使用Generic<Number>
作为形参的方法中,能否使用Generic<Ingeter>
的实例传入呢?在逻辑上类似于Generic<Number>
和Generic<Ingeter>
是否可以看成具有父子关系的泛型类型呢?
|
|
我们可以将上面的方法改一下:
|
|
此处’?’是类型实参,而不是类型形参 。再直白点的意思就是,此处的?和Number、String、Integer一样都是一种实际的类型,可以把?看成所有类型的父类。是一种真实的类型。
泛型的上界
在使用泛型的时候,我们还可以为传入的泛型类型实参进行上下边界的限制,如:类型实参只准传入某种类型的父类或某种类型的子类。
普通法的上界
上述例子
|
|
修改成
|
|
类的上界
上述例子
|
|
修改成
|
|
泛型方法的上界
|
|
泛型的下界
既然有了通配符的上界,自然有着通配符的下界。使用(? super ),类的父类都可以,子类不行,我们知道Integer是Number的一个子类,如果
|
|
泛型的使用
泛型有三种使用方式,分别为:泛型类、泛型接口、泛型方法。
泛型类
泛型类型用于类的定义中,被称为泛型类。通过泛型可以完成对一组类的操作对外开放相同的接口。最典型的就是各种容器类,如:List、Set、Map。
注意:泛型的类型参数只能是类类型,不能是简单类型;不能对确切的泛型类型使用instanceof操作。
|
|
泛型接口
|
|
泛型方法
泛型方法使得该方法能独立于类而产生变化。以下是一个基本的指导原则:无论何时,只要你能做到,你就应该尽量使用泛型方法。也就是说,如果使用泛型方法可以取代将整个类泛型化,那么就应该只使用泛型方法,因为它可以使事情更清楚明白。另外,对于一个static的方法而言,无法访问泛型类的类型参数。所以,如果static方法需要使用泛型能力,就必须使其成为泛型方法。
|
|
示例如下:
|
|
如果静态方法要使用泛型的话,必须将静态方法也定义成泛型方法如下:
|
|
泛型的示例
泛型数组
|
|
元组的使用
|
|
|
|
普通泛型
|
|
通配符
|
|
受限泛型
|
|
泛型无法向上转型
|
|
泛型接口
|
|
泛型方法
|
|
通过泛型方法返回泛型类型实例
|
|
使用泛型统一传入的参数类型
|
|
泛型数组
|
|
泛型的嵌套设置
|
|
参考:
http://blog.csdn.net/caihuangshi/article/details/51278793
http://www.cnblogs.com/sunwei2012/archive/2010/10/08/1845938.html
http://www.cnblogs.com/iyangyuan/archive/2013/04/09/3011274.html