jdk1.8之ArrayList源码分析(一)

最近有点空闲的时间,就对ArrayList进行了源码的查看。深思当ArrayList存在临界值时,该作者做了哪些操作.顺便记录下自己在源码中所了解的逻辑.这次博文入口显示添加和删除。

看过源码的都知道,ArrayList在初始化没有给定容器大小的时候,他会自动的帮我们创建一个10的集合大小.就是这段,他是在调用

 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

添加方法的时候,会判断是否是默认的共享实例 官方解释(/** * Shared empty array instance used for default sized empty instances. We * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when * first element is added. */)

程序发现是通过空的构造函数之后,在通过与当前的size+1的大小进行对比,通过max函数取最大的值,进行初始化容量.在确认过容量之后,此时的object对象还是一个空的无容量的集合,那么接下来就是对该空的数组赋容量.ensureExplicitCapacity调用改方法.

 if (minCapacity - elementData.length > 0)
            grow(minCapacity);

在该方法中该作者做了一个为防止溢出而做的一个过滤,那么什么情况下会出现这种情况呢。我们就给出一个int的最大值,假设这个数组的最大容量就是这个int的所能承受的最大值,那么此时改ArrayList在添加一个元素的时候,就是在最大值的时候加1也就是一个负数.带这个问题,我们来看下这个grow方法里面的状况.这个里面做的一些扩容的事情.那么我们就带着刚刚的那个不加过滤的问题,会出现什么情况.

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

当int newCapacity = oldCapacity + (oldCapacity >> 1)这个时;他的大小就是多少呢>>1其实就是一个二进制的一个右移动的一个过程然后在转10进制.具体的大家可以看下我这篇博文https://blog.csdn.net/ArryLuo123/article/details/81224930,那么当int进行移位了之后,再加上int的最大值,可想而知,他肯定就是一个负数。if (newCapacity - minCapacity < 0)一个绝对值大于一个添加的元素的绝对值时,两个数相减一定是一个负数,故,他就会赋值newCapacity = minCapacity;那么就会执行elementData = Arrays.copyOf(elementData, newCapacity);也就是newCapacity这个值就是一个负数的一个拷贝,故会出现这个异常java.lang.NegativeArraySizeException,那么接下来就是newCapacity - MAX_ARRAY_SIZE > 0这种情况了,这种情况是一种临界点,也就是int最大值和int最大值-8的一个相减而大于0的一种情况,其实也是一种溢出校验。通过层层把关之后,在调用elementData[size++] = e;进行赋值操作.

下面我们通过手写一个ArrayListdemo进行描述下,本demo不校验他们临界值以及各种情况,

/**
 * @author arryluo
 * 手写一个ArrayList
 *   //一个简单的仿ArrayList的一个添加操作。不涉及到临界溢出异常的处理,以及对数据是否合法进行校验,
 */
public class MyArryayList {
    int size=0;//这个是记录真实的数据容量大小,而不是数组的容量大小
    Object[]elementData={};//创建一个空的数组
    private static final int DEFAULT_CAPACITY = 10;
    public MyArryayList(){
        elementData= Arrays.copyOf(elementData, DEFAULT_CAPACITY);
    }
    public void add(Object o){
        elementData[size++]=o;
    }
    public int size(){
        return size;
    }
    //取出数据,不检测对该输入的角标是否大于真实数据的容量大小.
    public Object get(int index){
        return elementData[index];
    }
}

进行调用

public static void main(String[] args) {

        MyArryayList myArryayList=new MyArryayList();
        myArryayList.add("哈哈");
        System.out.println("真实容量:"+myArryayList.size());
        //进行遍历
        for (int i = 0; i <myArryayList.size() ; i++) {
           Object object= myArryayList.get(i);
            System.out.println(object);
        }


    }

执行结果

Connected to the target VM, address: '127.0.0.1:3141', transport: 'socket'
真实容量:1
哈哈
Disconnected from the target VM, address: '127.0.0.1:3141', transport: 'socket'

Process finished with exit code 0

针对为什么源码中给出的集合大小不是数组的真实大小。白话文,主要还是在遍历集合的时候,我们操作集合的数据以及大小的时候,如果用真实的,不便进行计算以及取值.同时也不便在添加数据的时候,进行一个扩容处理,具体可以往上面描述的进行查看,官方解释( minCapacity is usually close to size, so this is a win:).

流程图描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值