可变的数组-----集合类之ArrayList
经过前面的学习,都知道数组的长度是不可变的。可是在我们的实际开发中有些问题的大小是变化的,此时数组的长度定义大了,就会浪费内存空间,而小了的话就会不够用。为了解决这个问题我们引入了集合类。
集合类一共分为两大类:Collection和Map.
我们先从Collection开始讲起。
Collection
Collection本身是一个接口,他定义了集合应该有的方法,集合类中只能只能用来存储对象的引用,而非对象本身。
在Java中Collection本身并没有实现类,只有两个继承他的接口,而这两个接口各有各的实现类,用个图来表示他们之间的关系:
在这个图中只有第三行是具体的实现类,今天我们讲第一个:ArrayList。
ArrayList
凡是List接口实现的类,其集合内的元素都是有序的,可以重复的。ArrayList类的元素可以是任意类型的,包括Null,并且可以根据索引位置对集合进行访问,但其在插入和删除元素的操作方面效率极低。
下面我们来讲下他的方法。
ArrayList类在java.util这个包中,要使用这个类就必须要先导入这个包。
讲一个类就一定会先讲他的构造方法,否则练new对象都做不到,怎么调用其他的方法。
构造方法
1.public ArrayList();
我们来看一下他在源码中的实现:
public ArrayList() {
this(10);
}
这段代码何其的简单啊,我们从中只能得到一个信息,就是他调用了他本身的有参构造方法,并且传人了一个值:10.那么我们就去看看他的有参构造方法是如何写的。
2.public ArrayList(int initialCapacity)
我们来看看这个构造方法在源码中是如何写的:
public ArrayList(intinitialCapacity) {
super();
if (initialCapacity < 0)
thrownew IllegalArgumentException("Illegal Capacity: "+initialCapacity);
this.elementData =new Object[initialCapacity];
}
在这个代码中的if语句是用来判断输入的数是否小于0,如果小于0就抛出异常,因为集合的长度肯定是不小于0的整数。
最重要的下面的一句,他new了一个长度为传入的数,类型是Object的数组,将引用地址赋给了变量elementData这个变量在源码中是这样定义的:
privatetransient Object[]elementData;
这是个Object数组类型的引用变量。
从这可以看出ArrayList类的实现是建立在数组之上的,所以他可以通过索引来访问集合内的元素,同样他在内存中的存储也是一组连续的存储空间。
通过这个构造方法知道,我们用无参构造方法的时候,是先建立了一个容量为10的数组,我们也可以通过有参构造方法来根据我们的需要来建立一个容量为我们定义的数组。
下面讲一下集合类的操作添加,调用,删除。
集合元素的添加
集合可以添加是集合与数组最大的区别,他是同过这个方法来完成这个操作的:
publicboolean add(E e);
这个方法是用来在集合的末尾添加一个元素,如果添加成功就返回true,他的具体实现在源码中是这样写的:
publicboolean add(E e) {
ensureCapacity(size + 1);
elementData[size++] = e;
returntrue;
}
Size是添加前数组的实际长度,不包括没有赋值的数组元素,加一代表变化后的数组长度。这个方法调用了下面这个方法:
publicvoidensureCapacity(int minCapacity) {
modCount++;
int oldCapacity =elementData.length;
if(minCapacity > oldCapacity) {
Object oldData[] = elementData;
int newCapacity = (oldCapacity * 3)/2 +1;
if (newCapacity < minCapacity)
newCapacity = minCapacity;
elementData = Arrays.copyOf(elementData, newCapacity);
}
}
Array.copyOf方法是用来将传人的数组复制到目标数组里。
oldCapacity变量代表了数组当前的最大容量。从这个方法中我们可以看出,他是现将数组变化后的实际长度与数组当前的最大容量进行比较,如果大于最大容量,就将oldCapacity的值扩大1.5倍再加1,再与数组变化后的实际长度进行比较,如果大于数组变化后的实际长度就将现在oldCapacity最为数组现在的最大容量,否则就将数组变化后的实际长度作为数组的最大容量。
这就是ArrayList集合长度可以改变的原理。
集合元素的调用
集合元素调用用到了方法
public Object get(intindex);
这个方法传人的是元素在集合中的位置的索引值,就和调用数组元素一样。
需要说明的是在没有学习泛型之前,想要使用调用出来的元素必须进行显示的强制转换,因为返回的是Object而非你传入的类型。
集合元素的删除
对于 ArrayList 元素的删除操作,需要将被删除元素的后续元素向前移动,会严重影响程序的效率。
他会调用下面这两个方法:
1.public Object remove(intindex)
2.public boolean remove(Objecto)
第一种是按索引进行删除,第二种是按值来进行删除。比较好理解我就不多说了。
在下一篇我会讲解List接口的另一个实现LinkList.