一、什么是泛型;
泛型的本质是 参数化类型,也就是说 将所操作的数据类型 指定为一个参数,在不创建新类的情况下,通过参数来指定所要操作的具体类型(类似于方法中的变量参数,此时类型也定义成参数形式),也就是说,在创建对象或者调用方法的时候才明确下具体的类型。可以在类、接口、方法中使用,分别称为泛型类、泛型接口、泛型方法。
二、泛型的好处:
没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。
而引入泛型后,有如下好处:
1、消除显式的强制类型转换,提高代码可读性:
泛型中,所有的类型转换都是自动和隐式的,不需要强制类型转换,可以提高代码的重用率,再加上明确的类型信息,代码的可读性也会更好。
2、编译时的类型检查,使程序更加健壮:
对于强制类型转换错误的情况,编译期不会提示错误,在运行的时候才出现异常,这是一个安全隐患。泛型的好处是在编译期检查类型安全,并能捕捉类型不匹配的错误,避免运行时抛出类型转化异常ClassCastException,将运行时错误提前到编译时错误,消除安全隐患。
三、Java类库中的泛型有那些?泛型的用途?
(1)泛型类:最常见的用途就是容器类,通过泛型可以完成对一组类的操作对外开放相同的接口。所有的标准集合接口都是泛型化的---Collection<V>、List<V>、Set<V> 和 Map<K,V>。
(2)泛型接口:类似地,集合接口的实现都是用相同类型参数泛型化的,所以HashMap<K,V> 实现 Map<K,V> 等都是泛型的,Comparable和Comparator接口也是泛型的。
除了集合类之外,Java 类库中还有几个其他的类也充当值的容器。这些类包括 WeakReference、SoftReference 和 ThreadLocal。
(3)泛型方法:要定义泛型方法,只需将泛型参数列表置于返回值之前。
静态方法上的泛型:静态方法无法访问类上定义的泛型。如果静态方法操作的引用数据类型不确定的时候,必须要将泛型定义在方法上。如下:
四、泛型的上界下界:
<?extends T> 表示类型的上界,参数化类型可能是T 或者是 T的子类;
<? super T> 表示类型的下界,参数化类型是此T类型的超类型,直至object;
上界什么时候用:往集合中添加元素时,既可以添加T类型对象,又可以添加T的子类型对象。为什么?因为存的时候,T类型既可以接收T类对象,又可以接收T的子类型对象。
下界什么时候用:当从集合中获取元素进行操作的时候,可以用当前元素的类型接收,也可以用当前元素的父类型接收。
七、关于泛型的其他一些小细节:
1、可以创建泛型数组吗?相应的应用场景怎么处理?
不能创建泛型数组。一般的解决方案是任何想要创建泛型数组的地方都使用ArrayList?
2、可以将基本类型作为泛型参数吗?
泛型的类型参数只能是类类型(包括自定义类),不能是简单类型(基本数据类型)。
3、什么时候用泛型?
当接口、类及方法中的操作的引用数据类型不确定的时候,以前用的Object来进行扩展的,现在可以用泛型来表示。这样可以避免强转的麻烦,而且将运行问题转移到的编译时期。
4、泛型的细节:
(1)泛型实际代表什么类型,取决于调用者传入的类型,如果没传,默认是Object类型;
(2)使用带泛型的类创建对象时,等式两边指定的泛型类型必须一致。
原因:编译器检查对象调用方法时只看变量,然而程序在运行期间调用方法时就要考虑对象具体类型了。
(3)等式两边可以在任意一边使用泛型,在另一边不使用(考虑向后兼容);