ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

集合之arrayList源码解析

2021-05-16 15:35:27  阅读:114  来源: 互联网

标签:index Object int arrayList elementData 源码 解析 public size


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

 



 

标签:index,Object,int,arrayList,elementData,源码,解析,public,size
来源: https://www.cnblogs.com/wlong-blog/p/14773879.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有