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; }
  • 相关阅读:
    星月教你做网站(HTML5+CSS+JS)----html背景知识 HTML5环境安装 创建HTML5文档1(结构)
    带你学C带你飞--16拾遗 17数组
    神经网络
    交互项回归与分组回归有什么差异?
    逻辑回归输出的值是真实的概率吗?
    逻辑回归
    机器学习中的核函数与核方法
    Regularization for Logistic Regression: L1, L2, Gauss or Laplace?
    What is Wrong with Linear Regression for Classification?What is Wrong with Linear Regression for Classification?
    感知器算法
  • 原文地址:https://www.cnblogs.com/lkeji388/p/9797851.html
Copyright © 2011-2022 走看看