ArrayList深度解析

ArrayList 底层学习

底层知识

底层使用的是数组的数据结构

属性

//默认的初始化容量
private static final int DEFAULT_CAPACITY = 10;
//一个空的Object数组的实例(当使用有参构造器public ArrayList(int initialCapacity)时候自定义容量为0时候赋值给elementData)
private static final Object[] EMPTY_ELEMENTDATA = {};
//和上面一样是个空数组实例(当使用默认无参构造器时赋值给elementData)
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//真正的存放数组的数组
transient Object[] elementData;
//数组的长度
private int size;

构造器

 public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];//如果>0则直接立马给数组分配空间
        } else if (initialCapacity == 0) {
            //如果输入参数为0,那么就赋值一个空数组
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
 }

 public ArrayList() {
     	//可在属性中查看
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
 }

从这两个构造器中我们发现,如果我们给它一个整型参数且>0,那么会立马给elementData数组分配空间,如果为0则不管。但是如果调用无参构造器的时候我们发现他并没有分配空间,而是将它指向默认的空的elementData对象,但是并没有立马给他分配空间

newCapacity(int minCapacity)

//这个是将数组进行一个扩容操作,
private int newCapacity(int minCapacity) {
    	//保存旧数组的容量
        int oldCapacity = elementData.length;
    	//新数组的大小为旧数组+旧数组右移一位的和,相当于是扩大为原来1.5倍(newCapacity为扩容后的容量)
        int newCapacity = oldCapacity + (oldCapacity >> 1); 
    	//下面判断为真的例子
    	/*
    	当我们使用默认构造器时候,我们的elementData对象是一个空数组,
    	那么oldCapacity = elementData.length = 0
    	那么 newCapacity = oldCapacity + (oldCapacity >> 1) = 0
    	minCapacity = size + 1 ,此时size = 0,minCapacity = 1 
    	newCapacity - minCapacity = -1 <= 0
    	*/
        if (newCapacity - minCapacity <= 0) {
            //进入下面的判断分支说明使用的是默认构造器
            if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
                return Math.max(DEFAULT_CAPACITY, minCapacity);
            // overflow(内存溢出)
            if (minCapacity < 0) 
                throw new OutOfMemoryError();
            //如果使用有参构造器并且自定义capacity定义为0,就会使用下面的return,即返回1
            //(非常不建议这样,因为这样会导致数组不停的扩容,影响性能)
            return minCapacity;
        }
    	//这是正常的扩容容量,
        return (newCapacity - MAX_ARRAY_SIZE <= 0)  //判断新容量不超过最大容量的三目运算
            ? newCapacity //为真
            : hugeCapacity(minCapacity); //为假(分析可以看下面)
}

	
    private static int hugeCapacity(int minCapacity) {
        //内存已经用完了
        if (minCapacity < 0) 
            throw new OutOfMemoryError();
        //minCapacity已经超过定义的最大数组长度的三目运算
        return (minCapacity > MAX_ARRAY_SIZE)
            ? Integer.MAX_VALUE //为真(设置为最大的Int的最大数值容量)
            : MAX_ARRAY_SIZE; //为假(设置为定义的最大容量)
    }

add()方法

   //这个是扩容时调用的grow方法
	private Object[] grow(int minCapacity) {
        return elementData = Arrays.copyOf(elementData,//这里是将旧数组的信息复制到新数组中
                                           newCapacity(minCapacity));
    }

    private Object[] grow() {
        return grow(size + 1);
    }


	private void add(E e, Object[] elementData, int s) {
        	//这里的s传入的基本都是size
        	//当size的长度达到了数组的定义的长度时候就需要会进行扩容
            if (s == elementData.length)
                elementData = grow();   
        	//这里将数据保存进数组中,并且将size + 1 
            elementData[s] = e;  
            size = s + 1;
    }
	
	//平时调用的最多的方法
    public boolean add(E e) {
        //这个就是继续数组被更改的次数
        modCount++;
        //调用私有方法add
        Object[] elementData;
        if ((s = size) == (elementData = this.elementData).length)
            elementData = grow();
        System.arraycopy(elementData, index,
                         elementData, index + 1,
                         s - index);
        elementData[index] = element;
        size = s + 1;
    }
	
//-----------------------------下面为按下标进行一个插入操作---------------------------------------------
	
	private void rangeCheckForAdd(int index) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }


	
	/*
	这个方法我们可以明确的发现
	说明:只能插入在list的size以内的数据,相当于只能替换时候使用该方法,平时的插入还是以add(E e)为主
	*/
   public void add(int index, E element) {
       //对该下标进行一个判断,看看是否超过size或者index < 0	
        rangeCheckForAdd(index);
       //对数组修改操作 + 1
        modCount++;
        final int s;
        Object[] elementData;
       //和一个参数的add()方法一样,判断需不需要进行一个扩容操作
        if ((s = size) == (elementData = this.elementData).length)
            elementData = grow();
        System.arraycopy(elementData, index,
                         elementData, index + 1,
                         s - index);
       //将数据存储到数组中
        elementData[index] = element;
       //size + 1
        size = s + 1;
    }

Vector(线程安全)

底层也是使用的暴力加锁方法,直接使用synchronized修饰

如何选择线程安全的集合

1.可以选择线程安全的类,例如Vector,HashTable,ConcurrentHashMap

2.可以使用Collections.synchronized*(),这样的方法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值