zoukankan      html  css  js  c++  java
  • java基础源码 (6)--ArrayListt类

    原作出处:https://www.cnblogs.com/leesf456/p/5308358.html

    简介:

      1、ArrayList是一个数组队列,相当于动态数组。与java中的数组相比,它的容量能动态增长,它继承与AbstractList,实现List,RandomAccess,Cloneable,java.io.Serizlizable这些接口

      2、ArrayList继承AbstractList,实现了List,它是一个数组队列,提供了相关的增、删、改、遍历等功能

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

      4、ArrayList实现了Cloneable接口,即覆盖了函数clone(),能被克隆

      5、ArrayList实现了java.io.Serizlizable接口,这意味着ArrayList支持序列化,能通过序列化去传输。

      6、ArrayList不是线程安全的,在单线程中才使用

    数据结构:参考API1.8文档 的ArrayList

    java.lang.Object 
        java.util.AbstractCollection<E> 
            java.util.AbstractList<E> 
                java.util.ArrayList<E> 
    
    All Implemented Interfaces: 
    Serializable , Cloneable , Iterable <E>, Collection <E>, List <E>, RandomAccess 

     

    ArrayList构造函数:参考API1.8文档 的ArrayList

    ArrayList() 
    构造一个初始容量为十的空列表。  
    ArrayList(Collection<? extends E> c) 
    构造一个包含指定集合的元素的列表,按照它们由集合的迭代器返回的顺序。  
    ArrayList(int initialCapacity) 
    构造具有指定初始容量的空列表。  

    ArrayList包含了两个重要的对象:

      1、elementData:

        elementData是“Object []类型的数组”,它保存了添加到ArrayList中的元素。实际上,elementData是个动态数组,我们能通过构造函数ArrayList(int initialCapacity)来执行它的初始容量为initialCapacity;如果通过不含参数的构造函数ArrayList()来创建ArrayList,则elementData的容量默认是10,elementData数组的大小会根据ArrayList容量的增长而动态的增长

      2、size:

        size则是动态数组的实际大小。

    源码解析:

      类属性:类属性中核心的属性为elementData,类型为Object[],用于存放实际元素,并且被标记为transient,也就意味着在序列化的时候,此字段是不会被序列化的 

     //序列版本号
        private static final long serialVersionUID = 8683452581122892189L;
        //初始容量为10
        private static final int DEFAULT_CAPACITY = 10;
        //空对象数组
        private static final Object[] EMPTY_ELEMENTDATA = {};
        //(无参)缺省空对象数组
        private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
        //元素数组
        transient Object[] elementData; 
        //实际元素大小
        private int size;
        //最大数组容量

      private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

      类构造器:

        
    //指定elementData数组大小,不允许初始化大小,小于0,否则抛异常
    public ArrayList(int initialCapacity) { if (initialCapacity > 0) {//初始容量大于0 this.elementData = new Object[initialCapacity];//根据传入initalCapacity初始化元素数组 } else if (initialCapacity == 0) {//初始容量为0 this.elementData = EMPTY_ELEMENTDATA;//将属性的空对象赋值给元素数组 } else {//小于0,抛异常 throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } } /** *当为指定初始化大小时,会给elementData赋值为空集合
      */
    public ArrayList() {
          //将属性的无参空对象数组赋值给元素数组
            this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
        }
      //党传递的参数为集合类型时,会把集合类型转为数组类型,并赋值给elementData
        public ArrayList(Collection<? extends E> c) {
            elementData = c.toArray();//转为数组并赋值给元素数组
            if ((size = elementData.length) != 0) {//判断参数为非空集合
                // c.toArray might (incorrectly) not return Object[] (see 6260652)
                if (elementData.getClass() != Object[].class)//是否成功转为Object类型数组
                    elementData = Arrays.copyOf(elementData, size, Object[].class);//不为Object数组的话就进行复制
            } else {//判断参数为空,则将空对象数组赋值给元素数组
                // replace with empty array.
                this.elementData = EMPTY_ELEMENTDATA;
            }
        }

    核心函数:

      1、add:

        在add函数还有ensureCapacityInternal,此函数可以理解为确保elementData数组有合适的大小。

        public boolean add(E e) {//添加元素
            ensureCapacityInternal(size + 1);  // Increments modCount!!
            elementData[size++] = e;
            return true;
        }

      1.1、ensureCapacityInternal:

        在ensureCapacityInternal方法中ensureExplicitCapacity是为了确保elementData元素数组有合适的大小

       private void ensureCapacityInternal(int minCapacity) {
        
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//判断元素数组是否为空 minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);//取较大值 } ensureExplicitCapacity(minCapacity); }

      1.2、ensureExplicitCapacity:

        grow方法才会对数组进行扩容,1.1、1.2都只是过程,最后完成实际扩容操作是grow方法

      private void ensureExplicitCapacity(int minCapacity) {
            modCount++;//结构性修改+1
    
            // overflow-conscious code
            if (minCapacity - elementData.length > 0)
                grow(minCapacity);
        }

      1.3、grow:

        正常情况下会扩容1.5倍,特殊情况下(新扩展数组大小已达到最大值)则只取最大值

        private void grow(int minCapacity) {
            // overflow-conscious code
            int oldCapacity = elementData.length;//元素数组大小(旧容量)
            int newCapacity = oldCapacity + (oldCapacity >> 1);//新容量为旧容量的1.5倍
            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);
        }

      2、set:设定指定下标索引的元素值

    public E set(int index, E element) {
            rangeCheck(index);//检验索引是否合法,否则抛异常
    
            E oldValue = elementData(index);//旧值
            elementData[index] = element;//赋新值
            return oldValue;//返回旧值
        }

      3、indexOf:

        从头开始查找与指定元素相等的元素。注意是可以查找Null元素的,意味着ArrayList中可以存放null元素的。与此对应的lastIndexOf,表示从尾部开始查找

    //从首开始查找数组里面是否存在指定元素  
    public int indexOf(Object o) { if (o == null) {//判断元素是否为空 for (int i = 0; i < size; i++)//遍历数组 if (elementData[i]==null)//找到第一个为空的元素 return i;//返回它的下标 } else {//元素不为空 for (int i = 0; i < size; i++)//遍历数组 if (o.equals(elementData[i]))//找到第一个和指定元素相等的元素 return i;//返回下标 }
        
    return -1;//没有找到,返回-1 }

      4、get

       get方法会检查索引是否合法(只检查是否大于size,而没有检查是否小于0)

      public E get(int index) {
            rangeCheck(index);//检验索引是否合法
    
            return elementData(index);
        }

      4.1 、elementData:

        返回值都经过了向下 转型(Object(elementData元素数组是Object类型的)->E),这些是对我们应用程序屏蔽的小细节

       E elementData(int index) {
            return (E) elementData[index];
        }

      5、remove:

        移除指定下标的元素,此时会把指定下标到数组末尾的元素向前移动一个单位,并且会把数组最后一个元素设置为NUll,这样是为了方便之后将这个数组不被使用时,会被GC(垃圾回收),可以做为小的技巧使用

        public E remove(int index) {
            rangeCheck(index);//检查索引是否合法
    
            modCount++;
            E oldValue = elementData(index);
    
            int numMoved = size - index - 1;//需要移动的元素的个数
            if (numMoved > 0)
                System.arraycopy(elementData, index+1, elementData, index,
                                 numMoved);
        //赋值为空,有利于进行GC(垃圾回收) elementData[
    --size] = null; // clear to let GC do its work     //返回旧值 return oldValue; }
  • 相关阅读:
    PAT顶级 1015 Letter-moving Game (35分)
    PAT顶级 1008 Airline Routes (35分)(有向图的强连通分量)
    PAT顶级 1025 Keep at Most 100 Characters (35分)
    PAT顶级 1027 Larry and Inversions (35分)(树状数组)
    PAT 顶级 1026 String of Colorful Beads (35分)(尺取法)
    PAT顶级 1009 Triple Inversions (35分)(树状数组)
    Codeforces 1283F DIY Garland
    Codeforces Round #438 A. Bark to Unlock
    Codeforces Round #437 E. Buy Low Sell High
    Codeforces Round #437 C. Ordering Pizza
  • 原文地址:https://www.cnblogs.com/lkeji388/p/9797851.html
Copyright © 2011-2022 走看看