ArrayList类
- 数组结构实现,查询块、增删慢。
- JDK1.2版本加入,运行效率快、线程不安全。
1. ArrayList
ArrayList<Student> arrayList=new ArrayList<>();
// 1.添加元素
Student s1=new Student("唐", 21);
Student s2=new Student("何", 22);
Student s3=new Student("余", 21);
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
System.out.println("元素个数:"+arrayList.size());
System.out.println(arrayList.toString());
// 2.删除元素
arrayList.remove(s1);
// arrayList.remove(new Student("唐", 21));
// 注:这样可以删除吗(不可以)?显然这是两个不同的对象。
// 假如两个对象属性相同便认为其是同一对象,那么如何修改代码?
// 3.遍历元素
// 3.1使用迭代器
Iterator<Student> iterator=arrayList.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
// 3.2使用列表迭代器
ListIterator listIterator=arrayList.listIterator();
// 从前往后遍历
while(listIterator.hasNext()) {
System.out.println(listIterator.next());
}
// 从后往前遍历
while(listIterator.hasPrevious()) {
System.out.println(listIterator.previous());
}
// 4.判断
System.out.println(arrayList.isEmpty());
// System.out.println(arrayList.contains(new Student("何", 22)));
// 注:与上文相同的问题。
// 5.查找
System.out.println(arrayList.indexOf(s1));
2. ArrayList源码分析
ArrayList的扩容是原来的1.5倍。
默认容量大小:
private static final int DEFAULT_CAPACITY = 10;
存放元素的数组:
transient Object[] elementData;
实际元素个数:
private int size;
创建对象时调用的无参构造函数:
// 这是一个空的数组 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }
这段源码说明当你没有向集合中添加任何元素时,集合容量为0。那么默认的10个容量怎么来的呢?
这就得看看add方法的源码了:
public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; }
假设你new了一个数组,当前容量为0,size当然也为0。这时调用add方法进入到
ensureCapacityInternal(size + 1);
该方法源码如下:private void ensureCapacityInternal(int minCapacity) { ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); }
该方法中的参数minCapacity传入的值为size+1也就是 1,接着我们再进入到
calculateCapacity(elementData, minCapacity)
里面:private static int calculateCapacity(Object[] elementData, int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { return Math.max(DEFAULT_CAPACITY, minCapacity); } return minCapacity; }
上文说过,elementData就是存放元素的数组,当前容量为0,if条件成立,返回默认容量
DEFAULT_CAPACITY
也就是10。这个值作为参数又传入ensureExplicitCapacity()
方法中,进入该方法查看源码:private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); }
我们先不要管modCount这个变量。因为elementData数组长度为0,所以if条件成立,调用grow方法,重要的部分来了,我们再次进入到grow方法的源码中:
private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: elementData = Arrays.Of(elementData, newCapacity); }
这个方法先声明了一个oldCapacity变量将数组长度赋给它,其值为0;又声明了一个newCapacity变量其值为
oldCapacity+一个增量
,可以发现这个增量是和原数组长度有关的量,当然在这里也为0。第一个if条件满足,newCapacity的值为10(这就是默认的容量,不理解的话再看看前面)。第二个if条件不成立,也可以不用注意,因为MAX_ARRAY_SIZE的定义如下:private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
这个值太大了以至于第二个if条件没有了解的必要。
最后一句话就是为elementData数组赋予了新的长度,
Arrays.Of()
方法返回的数组是新的数组对象,原数组对象不会改变,该拷贝不会影响原来的数组。Of()
的第二个自变量指定要建立的新数组长度,如果新数组的长度超过原数组的长度,则保留数组默认值。这时候再回到add的方法中,接着就向下执行
elementData[size++] = e;
到这里为止关于ArrayList就讲解得差不多了,当数组长度为10的时候可以试着过一下源码,查一下每次的增量是多少(答案是每次扩容为原来的1.5倍)。