泛型初识


为什么需要泛型?

在Java没有泛型之前,类似于ArrayList这种为所有类提供相同功能的工具类为了保证泛用性,都是采用Object作为存储数据的类别。

在JDK1.5版本前,ArrayList等集合框架内部都有一个Object类型数组,通过这样的手段,集合框架就成了一个能持有多种对象的通用工具。

public class ArrayList {
    private Object[] array;
    private int size;
    public void add(Object e) {...}
    public void remove(int index) {...}
    public Object get(int index) {...}
}

这样就可以使用上述Arraylist存储StringUser等数据类型,但是这样存储有几个缺点:

  • 需要强制转型
  • 类型控制困难,使用不方便,易出错
ArrayList list = new ArrayList();
// 假如先存储了hello字符串到list中,在list中被转成Object
list.add("hello world");
String str = (String) list.get(0);

因为在list中是按照Object存储的,所以在使用get()方法取出来时必须强转为String

同样的,因为是使用Object类型来存储的,因此所以类型的数据都可以通过add()方法放入list

像下面这样使用add()方法,将Integer存入list时,不会产生错误。

list.add(new Integer(3123123));
String str2 = (String) list.get(1);

但是在使用get()方法获取到Integer对象,并且将其强转为String时,就会出现类型强转错误。

java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String

要解决这个问题,除非针对每一种类型都创建一个专属的ArrayList

public class ArrayList {
    private String[] array;
    private int size;
    public void add(String e) {...}
    public void remove(int index) {...}
    public String get(int index) {...}
}

但是这样的话,有多少类就需要多少创建多少个专属的ArrayList,实在是难以实现。

泛型

为了解决上述问题,在JDK1.5中,Java添加了泛型这一特性,有了泛型之后,ArrayList的代码就变为:

public class ArrayList {
    private T[] array;
    private int size;
    public void add(T e) {...}
    public void remove(int index) {...}
    public T get(int index) {...}
}

代码中的T可以是任意一种类型。任何一种类型都可以使用这个模板,比如String

ArrayList arrayList = new ArrayList<>();

使用泛型有一个更大的好处。在没有泛型前,使用Object类可以保存任意类,程序的错误只有在运行期才能检测出来。而使用了泛型后,像下面的代码中想要存入其他类型的数据时,编译阶段就会报错。

// 编译阶段就直接报错,
arrayList.add(new Integer(12344141));