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倍)。

Copyright © rootwhois.cn 2021-2022 all right reserved,powered by GitbookFile Modify: 2022-11-26 20:03:31

results matching ""

    No results matching ""