ArrayList源码解析及常见面试问题

简介

ArrayList 类
优点:尾插效率高,支持随机访问
缺点:中间插入或者删除效率低。

public class ArrayList<E> extends AbstractList<E>
       implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
  //初始容量10
 private static final int DEFAULT_CAPACITY = 10;
 //数组结构
 transient Object[] elementData; 
}

依赖关系

ArrayList依赖关系如下图
JDK1.8版本

常用方法

1:add方法

add方法有两个,默认在数组末尾插入,固定返回boolean比较简单;下面的值在指定位置插入

   public void add(int index, E element) {
   		//验证位置是否越界	
        rangeCheckForAdd(index);
		//扩容,默认长度的一半,存在特殊情况
		//特殊情况1,扩容为当前size+1
		//特殊情况2,扩容为 Integer.MAX_VALUE或者MAX_ARRAY_SIZE;
        ensureCapacityInternal(size + 1);
        //浅copy去改变下标,指定位置后面的数据全部右移一位
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        //空出的位置给添加的对象                 
        elementData[index] = element;
        //长度+1
        size++;
    }

简单介绍下System.arraycopy,用的挺多的,效率比循环快

     * src表示源数组
     * srcPos表示源数组中拷贝元素的起始位置。
     * dest表示目标数组
     * destPos表示拷贝到目标数组的起始位置
     * length表示拷贝元素的个数
     */

    public static native void arraycopy(Object src,  int  srcPos,
                                        Object dest, int destPos,
                                        int length);

2:remove方法

remove方法也有两个,

  • 指定下标删除
public E remove(int index) {
      //检查下标是否越界
      rangeCheck(index);
      //数组操作的次数,主要迭代时使用,如果迭代时发现次数改变,则异常
      modCount++;
      //取出删除的值,返回使用
      E oldValue = elementData(index);
      //改变的元素个数, 例如index=2,集合存的0~9十个元素,size=10,则0,1后面七个元素被改变,10-2-1=7
      int numMoved = size - index - 1;

      if (numMoved > 0)
          //指定位置后面的数据全部左移一位
          System.arraycopy(elementData, index+1, elementData, index,
                           numMoved);
      //最后一位制为null,让GC去删除
      elementData[--size] = null; // clear to let GC do its work
      //返回删除的值
      return oldValue;
  }
  • 删除指定对象
  public boolean remove(Object o) {
       if (o == null) {
       //循环找到对应的值的下标,然后删除,删除操作与上面remove相似。只删除一个。
           for (int index = 0; index < size; index++)
               if (elementData[index] == null) {
                   fastRemove(index);
                   return true;
               }
       } else {
           for (int index = 0; index < size; index++)
               if (o.equals(elementData[index])) {
                   fastRemove(index);
                   return true;
               }
       }
       return false;
   }

有个小疑问,为什么上面的remove方法不写成下面的样子,清楚地同学可以留言说一下。

 public boolean remove(Object o) {

        for (int index = 0; index < size; index++)
            if (elementData[index] == null || o.equals(elementData[index])) {
                fastRemove(index);
                return true;
            }
        return false;
    }

3:get方法

没啥说的,根据下标查出来

 public E get(int index) {
        rangeCheck(index);

        return elementData(index);
    }

4:set方法

虽然是set,但是更新操作,不是新增操作。

  public E set(int index, E element) {
        rangeCheck(index);
        //取出旧值,返回用
        E oldValue = elementData(index);
        //更新指定下标对应的值
        elementData[index] = element;
        return oldValue;
    }

常见的面试问题

  • ArrayList的大小如何自动增加的
    看上面的add方法就是答案,简单说每次add都会扩容,默认增加size的一半。

  • 什么情况你会使用ArrayList
    一般听到这个问题就有点苦恼,这不是基本操作吗,还用问???
    可以简单说,数据库读取数据时使用,因为有序且不需要删除操作,效率高。

  • 在索引中ArrayList的增加或者删除某个对象的运行过程,效率很低吗,为什么?
    效率肯定低了,因为arrayCopy 操作耗费内存。

  • ArrayList如何顺序删除节点
    迭代器是顺序删除的,for循环也可以,不过要从list的尾部开始删除,因为从头部删除,头部会被后面数据覆盖,头部下标依然有数据。

  • ArrayList的遍历方法
    迭代器 hasNext方法,for循环遍历,foreach和上题一样

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值