ArrayList面试系列

Posted ringbug

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ArrayList面试系列相关的知识,希望对你有一定的参考价值。

ArrayList扩容机制为什么是1.5倍+1

这里是自己参考jdk [version "1.8.0_144"] ,也是目前正在使用的

  • 类实现
public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
  • 重要属性
/**
     * 默认初始容量
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * 用于空实例的共享空数组实例.
     */
    private static final Object[] EMPTY_ELEMENTDATA = ;

    /**
     * 用于默认大小的空实例的共享空数组实例,ArrayList的容量是此数组缓冲区的长度
     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = ;

    /**
     * 存储ArrayList元素的数组缓冲区.
     */
    transient Object[] elementData; // 非私有,以简化嵌套类访问

    /**
     * ArrayList的大小(它包含的元素数).
     */
    private int size;
    
    /**
     * 结构修改的次数
     */
    protected transient int modCount = 0;

Java中transient关键字的作用,简单地说,就是让某些被修饰的成员属性变量不被序列化

  • 1.size是数据的个数!elementData.length是elementData的c长度(包含被元素占用的空间和预留的空间)
public boolean add(E e) 
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    

将现在的长度size加一后,传进ensureCapacityInternal里面

  • 2.DEFAULTCAPACITY_EMPTY_ELEMENTDATA是空数组,表示现在ArrayList是空的
private void ensureCapacityInternal(int minCapacity) 
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) 
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        

        ensureExplicitCapacity(minCapacity);
    

ensureCapacityInternal中首先是判断现在的ArrayList是不是空的,如果是空的,minCapacity就取默认的容量和传入的参数minCapacity中的大值
然后调用ensureExplicitCapacity方法

  • 3.modCount是fail fast机制,在jdk1.6之前都是有volatile来修饰的,尽可能的让并发访问非安全的集合对象时尽快的失败抛出异常,让程序员修改代码
private void ensureExplicitCapacity(int minCapacity) 
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);

在jdk1.7中去掉了volatile修饰,因为感觉没有必要为非线程安全集合浪费效率,在jdk1.5开始就提供了线程安全的集合类,在多线程环境下就应该使用线程安全的集合。
接着看,如果minCapacity的值大于add数据之前的大小,就调用grow方法,进行扩容,否则什么也不做

  • 4.注意:这里传过来的minCapcatiy的值是size+1,能够实现grow方法调用就肯定是(size+1)>elementData.length的情况,所以size就是初始最大容量或上一次扩容后达到的最大容量,所以才会进行扩容
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.copyOf(elementData, newCapacity);
    

newCapacity=oldCapacity+(oldCapacity>>1),这里就是扩容大小确定的地方,相当于新的最大容量是 size+1;size=1+0.5
相当于原来的1.5倍然后加1


  • 参考文章

  • 这里并没那么的太详细,如果有不明白的小伙伴可以在下方发私信,大家一起交流!

以上是关于ArrayList面试系列的主要内容,如果未能解决你的问题,请参考以下文章

(第一期)大厂面试系列_ArrayList 公众号java源码栈

日拱一卒进击大厂系列ArrayList的面试陷阱别跳进去了

日拱一卒进击大厂系列ArrayList的面试陷阱别跳进去了

福利时刻Java面试题84集系列全集!

阿里面试官:说一下ArrayList和LinkedList的区别?

面试系列文章