在没有泛型之前,一旦把一个对象“丢进”Java集合中,集合就会忘记对象的类型,把所有对象当成Object类型处理,当程序从集合中取出对象后,就需要进行强制类型转换,这种强制类型转换不仅使代码臃肿,而且容易引起ClassCastException异常。
Java7以后提供了一个菱形语法,在Java7以前,泛型的声明必须前后都指定类型,如下所示:
List strList=new ArrayList();
菱形语法的声明如下:
List strList=new ArrayList<>();
编译器会自动推断出后面的类型。所谓泛型,就是允许在定义类、接口、方法时使用类型形参,这个类型形参将在声明变量、创建对象、调用方法时动态地指定(即传入实际的类型参数,也可称为类型实参)。泛型示例如下代码所示:
[Java Code]
class Apple<E> {
private E info;
public Apple(E info) {
this.info = info;
}
public void setInfo(E info) {
this.info = info;
}
public E getInfo() {
return this.info;
}
}
当创建带泛型声明的自定义类,为该类定义构造器时,构造器名还是原来的类名,不要增加泛型声明。当创建了带泛型声明的接口、父类之后,可以为接口创建实现类,或从该父类派生子类,但需要指出的是,当使用这些接口、父类时不能再包含类型形参。如果想从Apple类中派生一个子类,需要指定Apple的实际形参类型(也可以不指定,但会看到编译器警告,泛型参数会被默认当成Object来处理)。
public class A extends Apple<String>
不管泛型的实际类型参数是什么,它们在运行是总有同样的类(class),在Java中,在内存中只占用一块内存空间,因此在静态方法、静态初始化块或者静态变量的声明和初始化中不允许使用类型参数。
类型通配符:
如果Foo是Bar的一个子类型(子类或者子接口),而G是具有泛型声明的类或接口,G并不是G的子类型。数组和泛型有所不同,假设Foo是Bar的一个子类型(子类或者子接口),那么Foo[]依然是Bar[]的子类型,但是G不是G的子类型。类型通配符是一个问号?,将一个问号作为类型实参传给List集合,写作:List<?>。如果规定限定是某父类的子类时可以使用如下通配符:List<? extends Father>。如果规定限定某子类的父类可以使用如下通配符:List<? super Son>。把泛型变量赋值给非泛型变量,会擦除泛型变量中的类信息,转为原生类型。