java的泛型看了几遍,由于平时不怎么使用,所以总是记不住,但是泛型在做公共组件开发等场景中,是必备知识,所以在这里整理了一下,希望可以理解得更深入。下图是我在看《疯狂Java讲义》中泛型这一章整理出来的逻辑思维导图:
泛型在这本书里也是一章内容,所以这篇文章不会全部囊括,主要会写我一直没有真正理解和完全记住的一些点。
为什么需要泛型:
JDK1.5增加泛型支持很大程度上都是为了让集合能记住其元素的数据类型。
在没有泛型之前,一旦把一个对象“丢进”java集合中,集合就会忘记对象的类型,把所有的对象当成Object类型处理。当程序从集合中取出对象后,就需要进行强制类型转换,这种强制类型转换不仅代码臃肿,而且容易引起ClassCastExeception异常。
定义:
所谓泛型,就是允许在定义类、接口时指定类型形参,这个形参将在声明变量、创建对象时确定(即传入实际的类型参数,也可称为类型实参)。
定义接口:
//定义接口时指定了一个类型形参,该形参名为E(E是随便指定的,没有实际意义,这里只是声明一下以便在类中可以使用,如下)
public interface List<E> extends Collection<E>
{
//在接口里,E可以作为类型使用
//下面方法可以使用E作为参数类型
void add(E x); --》写一类的方法,需要指定参数的类型,避免添加不符合类型的数据
Iterator<E> iterator(); --》 读一类的方法,返回值需要指定类型,避免擦除泛型的类型
}
public interface Iterator<E>
{
E next();
boolean hasNext();
}
public interface Map<K,V>
{
Set<K> keySet();
V put(K key, V value);
}
定义类
//定义Apple类时使用了泛型声明
public class Apple<T>
{
//使用T类型形参定义属性
private T info;
public Apple(){}
public Apple(T info) {
this.info = info;
}
public void setInfo(T info) {
this.info = info;
}
public T getInfo(){
return this.info;
}
}
定义方法
泛型方法:在声明方法时定义一个或多个类型形参。
//泛型方法的格式,中间<T,S>为类型形参的声明
修饰符 <T,S> 返回值类型 方法名(形参列表)
{
//方法体
}
static <T> void fromArrayToCollection(T[] a,Collection<T> c)
{
for (T o : a)
{
c.add(o);
}
}
类型通配符
为什么需要类型通配符:假设Foo是Bar的一个子类型(子类或者子接口),但G< Foo>不是G< Bar>的子类型。在下面的接口中:
public void test(List c)
{
for(int i=0;i<c.size();i++)
{
System.out.println(c.get(i));
}
}
由于List是一个有泛型声明的接口,此处使用List接口时却没有传入实际类型参数,这将引起泛型警告。为了接口的通用性,如果设定List c为List< Object> c,但是这样如果实参是List< String>将会报错,因为List< String>不是List< Object>的子类,所以在这里我们需要一个通配符“?”。List< ?>是表示它是各种泛型List的父类,包括List< Object>或者List< String>等。
我们还可以给这个通配符设定上限,比如List< ? extends Integer>甚至是泛型的上限List< ? extends T>;也可以给类型形参设上限,比如List< T extends String>。