zoukankan      html  css  js  c++  java
  • 集合之ArrayList源码解析

    public class ArrayList<E> extends AbstractList<E>
            implements List<E>, RandomAccess, Cloneable, java.io.Serializable

    arrayList 是我们平时开发中最常用的集合了,利用空闲时间来看一下对应源码。

    类图如下:

    实现了接口:List ,RandomAccess, Cloneable, java.io.Serializable

    public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable

    其中RandomAccess, Cloneable, Serializable接口,我们点进去可以发现是空接口,并没有任何实现方法。

    RandomAccess表示Arraylist 可以进行快速的随机访问,arraylist 特性为访问速度快,删除添加慢;与之对应的LinkedList 查询慢,删除添加速度快;

    Cloneable表示可以进行clone,这个接口起到一个标记作用,告诉jvm 这个可以进行clone ,没有则抛出异常,一般我们实现clone ,先调用supper.clone();

    Serializable表示序列化,java序列化是指将java 对象转化为字节序列的过程,反序列化是指将字节序列恢复至java对象的过程。

    序列化IO:

    1. java.io.ObjectOutputStream:表示对象输出流 它是OutputStream类的一个子类,对应的ObjectOutputStream.WriteObject(Object object)就要求参数object实现Serializable接口。

    2. java.io.ObjectInputStream:表示对象输入流 ,它的readObject(Object object)方法从输入流中读取字节序列,再把它们反序列化成为一个对象,并返回。

    java 中一般我们创建实体类 需要实现 Serializable 接口 ,然后 添加对应的serialVersionUID;

    Java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,

    可以进行反序列化,否则就会出现序列化版本不一致的异常(InvalidCastException)

    serialVersionUID 有两种写法:(1)根据类名,接口名,字段属性生成的64位哈希字段 private static final long serialVersionUID = 5490009942423030040L; (2)默认1L private static final long serialVersionUID=1L;

    若是字段不想进行反序列化可以添加transcient 修饰。

    属性:

    private static final int DEFAULT_CAPACITY = 10;
    
    private static final Object[] EMPTY_ELEMENTDATA = {};
    
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    
    transient Object[] elementData;

    构造函数:
    默认无参构造:可以看出当我们new ArrayList()时候,初始化并没有进行开辟空间存放元素,当添加元素是初始化容量为10 .

     public ArrayList() {
            this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
        }

    有参构造: 初始化容量大于 0 时,创建 Object 数组 ;  初始化容量等于 0 时,使用 EMPTY_ELEMENTDATA 对象

      public ArrayList(int initialCapacity) {
            if (initialCapacity > 0) {
                this.elementData = new Object[initialCapacity];
            } else if (initialCapacity == 0) {
                this.elementData = EMPTY_ELEMENTDATA;
            } else {
                throw new IllegalArgumentException("Illegal Capacity: "+
                                                   initialCapacity);
            }
        }

    参数为集合,如果集合元素不是 Object[] 类型,则会创建新的 Object[] 数组,并将 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)
                    elementData = Arrays.copyOf(elementData, size, Object[].class);
            } else {
                // replace with empty array.
                this.elementData = EMPTY_ELEMENTDATA;
            }
        }

    最大数组长度:private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    新增元素 add :

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

    private void ensureCapacityInternal(int minCapacity) { ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); }
      private static int calculateCapacity(Object[] elementData, int minCapacity) {
    //如果数组为空情况下 比较默认值和传入的数组长度大小 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { return Math.max(DEFAULT_CAPACITY, minCapacity); } return minCapacity; }
    private void ensureExplicitCapacity(int minCapacity) {
    modCount
    ++; // overflow-conscious code
    if (minCapacity - elementData.length > 0) grow(minCapacity);
    }

    grow() 扩容: 扩容至原数组长度的1.5倍

     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);
        }

    指定下标添加:

          public void add(int index, E element) {
    //检查index 是否在数组范围内 rangeCheckForAdd(index); ensureCapacityInternal(size
    + 1); // Increments modCount!!

    //将index +1 之后的元素向后挪一位copy赋值 System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; }

    数组缩容:

    public void trimToSize() {
            modCount++;
            if (size < elementData.length) {
                elementData = (size == 0)
                  ? EMPTY_ELEMENTDATA
                  : Arrays.copyOf(elementData, size);
            }
        }

    检测主动扩容:ensureCapacity  

     public void ensureCapacity(int minCapacity) {
            int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
                // any size if not default element table
                ? 0
                // larger than default for default empty table. It's already
                // supposed to be at default size.
                : DEFAULT_CAPACITY;
    
            if (minCapacity > minExpand) {
                ensureExplicitCapacity(minCapacity);
            }
        }

    添加集合元素:避免多次扩容 ,提高效率

     public boolean addAll(Collection<? extends E> c) {
            Object[] a = c.toArray();
            int numNew = a.length;
            ensureCapacityInternal(size + numNew);  // Increments modCount
            System.arraycopy(a, 0, elementData, size, numNew);
            size += numNew;
            return numNew != 0;
        }

    移除元素:需要判断移除元素是否为null ,fastRemove() : size - index - 1 判断移除元素是否是最后一个;

    elementData[--size] = null; // clear to let GC do its work 移除元素后将最后一位置为null 方便GC
    public boolean remove(Object o) {
            if (o == null) {
                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;
        }

    private void fastRemove(int index) {
    modCount++;
    int numMoved = size - index - 1;
    if (numMoved > 0)
    System.arraycopy(elementData, index+1, elementData, index,
    numMoved);
    elementData[--size] = null; // clear to let GC do its work
    }

    清除元素:clear ()  遍历将元素置为null   size=0

    public void clear() {
            modCount++;
    
            // clear to let GC do its work
            for (int i = 0; i < size; i++)
                elementData[i] = null;
    
            size = 0;
        }

    替换对应下标的元素: 

    public E set(int index, E element) {
    //检测下标是否超过列表size rangeCheck(index);      //将对应位置的元素替换 E oldValue
    = elementData(index); elementData[index] = element; return oldValue; }

    获取元素在列表中的下标:indexOf(),没有找到返回-1

    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;
        }

    判断列表中是否包含元素:contains   实际上调用的是indexOf ()

    public boolean contains(Object o) {
            return indexOf(o) >= 0;
        }

    克隆:调用supper.clone() 

     public Object clone() {
            try {
                ArrayList<?> v = (ArrayList<?>) super.clone();
                v.elementData = Arrays.copyOf(elementData, size);
                v.modCount = 0;
                return v;
            } catch (CloneNotSupportedException e) {
                // this shouldn't happen, since we are Cloneable
                throw new InternalError(e);
            }
        }

    转化为数组:toArray 返回的为Object 数组 因此我们在进行列表转数组的时候需要使用 toArray(T[] a)

     public Object[] toArray() {
            return Arrays.copyOf(elementData, size);
        }

    public <T> T[] toArray(T[] a) {
    if (a.length < size)
    // Make a new array of a's runtime type, but my contents:
    return (T[]) Arrays.copyOf(elementData, size, a.getClass());
    System.arraycopy(elementData, 0, a, 0, size);
    if (a.length > size)
    a[size] = null;
    return a;
    }

     阿里开发规范为:

    创建 ArrayList 的子数组  subList(int fromIndex, int toIndex),返回原列表上的截取元素列表,返回值会随着原列表改变而改变

     public List<E> subList(int fromIndex, int toIndex) {
            subListRangeCheck(fromIndex, toIndex, size);
            return new SubList(this, 0, fromIndex, toIndex);
        }


  • 相关阅读:
    Navicat连接mysql提示1251解决方案
    js获取select下拉框选中的值
    Windows下安装Mysql数据库
    ASP.NET MVC API以及.Core API进行安全拦截和API请求频率控制
    myeclipse 10.7中文破解版 下载安装看着一篇就够了
    Runtime exception at 0x004000bc: invalid integer input (syscall 5)
    MARS(MIPS汇编程序和运行时模拟器)
    如何将本地的代码上传到github
    JavaWeb基础
    大学什么时候开学?这款小程序告诉你!
  • 原文地址:https://www.cnblogs.com/wlong-blog/p/14773879.html
Copyright © 2011-2022 走看看