ArrayList的底层是数组,Object[]数组能存储不同类型的数据,只不过ArrayList在Object[]基础上结合泛型做了一层封装。
难用的数组
假设现在是JDK1.4的年代,你正在自己的IDE上编程:
当你需要往数组添加元素时,为了避免不小心覆盖已有的元素,你要时刻记住当前最新的index的值!是不是想骂人了?倒也不必,只需要每次使用时遍历出第一个为null的元素的位置即可。
虽然会消耗点性能,但好歹用起来省心。但还有个问题没解决:Java数组一旦初始化,长度就是固定的。上面的addElement方法虽然能避免ArrayIndexOutOfBoundsException,但缺点是数组满了以后会拒绝加入新元素,不会自动扩容。
支持动态扩容
为了解决这个问题,我们可以尝试把String数组包装成DynamicStringArray:
DynamicStringArray添加元素时无需考虑index的位置,并且支持自动扩容,极大减轻了使用者的心智负担。
加入泛型
你得意地开始在组内推广自己写的DynamicStringArray,却立刻遭到了同事的挑战:如果我要存的是Integer怎么办?你这才意识到,DynamicStringArray并不是一个通用的数组,它只为String类型服务!难道要再写一个DynamicIntegerArray?Person、Student、Department又该如何?
正当你陷入了迷茫的时候,Sun公司的一个员工也在思考这个问题。他发现,DynamicIntegerArray与DynamicStringArray唯一的区别就是元素类型,如果能对类型进行抽象,就能复用这套"动态数组"的逻辑。
具体怎么做呢?抽象!比如:
我们对1、2进行数据抽象得到Integer:
相似地,我们对数据类型进行类型抽象:
a是对数据的抽象,T是对类型的抽象
T被称为形式类型参数,类似我们常说的"形参",与之对立的是实际类型参数,是给它赋值的。
Java没有泛型数组,ArrayList底层用的是Object数组,但泛型可以进行约束
DynamicArray是一个通用的模板类,适用于任意类型的元素,同时还能进行编译时类型校验:
将DynamicArray的T"赋值"为Integer,表示:arr只处理Integer类型的元素