Java基础 | 从源码看一看ArrayList的几个常见方法


从源码看一看ArrayList的几个常见方法

第一节 ArrayList简介

  • ArrayList是一个数组队列,相当于动态数组。与Java中的数组相比,它的容量能动态增长。它继承于AbstractList,实现了List,RandomAccess[随机访问],Cloneable[可克隆],java.io.Serializable[序列化]这些接口。ArrayList继承了AbstractList,实现了List,提供了相关的添加、删除、修改、遍历等功能。

  • ArrayList实现了RandmoAccess接口,即提供了随机访问功能。RandmoAccess是java中用来被List实现,为List提供快速访问功能的。在ArrayList中,可以通过元素的序号快速获取元素对象,即快速随机访问。

  • ArrayList 实现了Cloneable接口,即覆盖了函数clone(),能被克隆。ArrayList 实现java.io.Serializable接口,这意味着ArrayList支持序列化,能通过序列化去传输。

  • 与Vector不同,ArrayList中的操作不是线程安全的。所以,建议在单线程中才使用ArrayList,而在多线程中可以选择Vector或者CopyOnWriteArrayList。

第二节 增删查改源代码解析

2.1 增加

  ArrayList添加元素的操作,这里介绍两个方法 add(E object)add(int index, E object) 。其他的方法,类似addAll(int index, Collection<? extends E> c)等,自行探索即可。

  • add(E object)方法
      add(E object)方法的结果是在list末尾增添新元素,源码如图2-1所示。

    图2-1 add(E object)方法源码

              
      可以看到add()方法首先使私有属性modCount自增。然后调用私有方法add(E e, Object[] elementData, int s),最后返回。add(E e, Object[] elementData, int s)方法首先检查List长度,若目前List长度等于size,则会调用grow()方法进行扩容。grow()方法如图2-2所示:

图2-2 grow()方法

  如果原有List不空,旧List长度加一,并进行新旧List的复制;若原有List长度为0,就new一个新List。
  调用grow()方法之后,将新加入的元素放置在末尾,List的size属性自增。

  • add(int index, E object)方法
    add(int index, E object)是指在 index的位置 ,插入一个新元素,源码如图2-3所示。
    图2-3 add(int index, E object)方法
      可以看到,首先对添加位置进行了合法检查,之后,若现有List长度不够,调用grow()方法对原有List容量加一,之后调用arraycopy方法对插入位置之后的元素进行复制。最后将待插入元素插入应插入空位,List的size属性加一。


2.2 删除

  • remove(int index)方法
     remove(int index)方法的结果是删除指定位置的元素。源码如图2-4所示:
    图2-4 remove(int index)方法
      remove()方法首先检查删除位置是否符合删除要求,调用fastRemove()方法进行元素的删除。fastRemove()方法源码如图2-5所示:
    图2-5 fastReove()方法
      即如果size-1大于将删除的位置,将待删除位置之后所有元素向前移动,如果删除后List为空,返回null。


  • remove(Object object)方法
      remove(Object object)的结果是删除某个已知元素,源码如图2-6所示:
    图2-6 remove(Object object)方法
      通过循环遍历,并进行比较找到对应的index。

  这里有两点需要注意:
   1. 传入null情况:
    删除掉第一个null元素。
   2. 顺序删除问题:
    ArrayList是可以顺序删除节点的,如果使用普通for循环,必须是从后往前删。
示例代码如下:

    public static void main(String[] args) {
           ArrayList list = new ArrayList();
           list.add("a");
           list.add("b");
           list.add("c");

           System.out.println("删除前:" + list.toString());

           for (int i = 0; i < list.size(); i++){
               list.remove(i);
           }
           System.out.println("删除后:" + list.toString());    
        } 
    }

  输出结果如图2-7所示:

图2-7 错误结果
  出错原因分析如下:

   要顺序删除ArrayList的全部节点,如果我们从前往后的顺序删除,先删除【0】位置的数据,但是由于删除的时候是从后往前挪一位进行删除的,所以【0】的位置又会被下一个位置的数据覆盖上,实际上【0】还是有数据的。



  正确代码如下:

    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        list.add("a");
        list.add("b");
        list.add("c");

        System.out.println("删除前:" + list.toString());

        for (int i = list.size() - 1; i >= 0; i--) {
            list.remove(i);
        }
        System.out.println("删除后:" + list.toString());
    }
}

  输出结果如2-8所示:

图2-7 正确结果

  所以,如果自定义类想要使用remove方法从列表删除某个指定值对象, 还需要实现该类型自己的equals方法才行!



  当然了,清除List中所有元素可以调用clear()方法。



2.3 查改

  • get(int index)方法
     get(int index)方法的结果是查找指定位置的元素。源码如图2-8所示:
    图2-8 get(int index)方法
      get()方法首先检查查找位置是否符合要求,之后调用elementData方法返回相应位置的元素,elementData()方法源码如图2-9所示:
    图2-9 elementData(int index)方法


  • set(int index, E element)方法
     set(int index, E element)方法的结果是将index位置元素设置为element元素。源码如图2-10所示:
    图2-10 set(int index, E element)方法
      set(int index, E element)方法首先检查修改位置是否符合要求,之后取出修改之前的元素,修改相应位置元素,返回修改前的元素。这里说明一下,返回元素可以不接收,仅是调用修改。




第三节 ArrayList其他常用方法

  • size()方法
      顾名思义,求取List长度,源码短的不好意思放出来了,就是直接将size返回。

  • isEmpty()方法
      依旧顾名思义,判断List是否为空。

  • indexOf(Object o)方法
      返回查找对象o第一次出现在List中的下标,如图3-1所示,可以看到,分为了对象是否为null进行顺序查找。

    图3-1 indexOf(Object o)方法
  • contains(Object o)方法
      判断List中是否有对象o,返回值为boolean类型。



这里就介绍这么多,更多的方法可以查看Java API规范,这里的链接是JDK 13版本的 Java API规范,或者直接在调用某方法的方法名上,Ctrl + 左键,跳转到源码的位置。


文章作者: Demerzel Sun
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Demerzel Sun !
评论
 上一篇
算法设计与分析第二次作业 算法设计与分析第二次作业
算法设计与分析第二次作业1. 证明或否证: $ f\left( n \right) +o\left(f\left( n \right) \right)=\varTheta\left(f\left( n \right) \right) $证明
本篇 
Java基础 | 从源码看一看ArrayList的几个常见方法 Java基础 | 从源码看一看ArrayList的几个常见方法
从源码看一看ArrayList的几个常见方法第一节 ArrayList简介 ArrayList是一个数组队列,相当于动态数组。与Java中的数组相比,它的容量能动态增长。它继承于AbstractList,实现了List,RandomAcce
2020-03-03
  目录