暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Java_ArrayList源码阅读

深文笔记 2021-06-21
161

    不出意外的话, ArrayList 这个集合,我们平常在写代码的时候,肯定是使用到非常多的。竟然我们使用了这么多,那我们是不是应该看下 ArrayList 这个类呢.  快上车,上了就别想下来了,车门都给你焊死hhhhh.



先来看下ArrayList的上级,可以看到最上面有一个迭代器,这个是不是想到了有一种设计模式叫迭代器设计模式?




这里,我们直接一步到位,点到源码里面来.  我们接下来就分析这几个我们经常在代码里面使用到的方法,看看这些方法是怎么实现的?



在我们new一个对象的时候,然后调用其方法,我个人认为在这之前,应该在去看一下这个对象的属性.

所以,这里我上属性,给大家过过眼.

是可以看到,属性并不是特别多,还是可以理解的.  主要看 elementData这个属性,因为我们的ArrayList就是利用数组来存储数据的.

    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;




    了解完属性后,接着我们就根据 add 添加元素方法.  这里我就不将代码一行行的贴出来,直接拿主要的部分来进行阅读. 

    如果走到了grow,就是需要进行扩容了,那么ArrayList是怎么扩容的?每次扩容又是扩容多少呢?如果是第一次并且没有指定集合大小的话,默认值是10.

    如果不是第一次,那么minCapacity的指是 size + 1.

    先将 elementData的数组长度扩大1.5倍,然后与 minCapacity和MAX_ARRAY_SIZE进行比较,最后得出  newCapacity的值来.

    最后调用 Arrays.copyOf来扩容.

    最后扩容完了,调用elementData[size++] = e; 将新添加的数据放在最后一位.




    再来一个根据下标来添加数据代码.

    先是检查下标是否越界,再是调用是否需要扩容的方法.

    比如我现在集合有十个元素? 我往第五个插入一个字符串的值是: "PeterWong", 那我是不是将从第五开始后的元素都往后移动一位呢?但是这里并没有发现往后移动赋值的for循环代码呀?那是因为 System.arrraycopy 给我们做了一件这样的事情. 看下图的结果,可以看到System.copyof是将index的值给复制了一份,然后ArrayList再调用 elementData[index] = element给覆盖掉了. 所以我们没有看到for循环去移动值,是因为 System.copyof帮我们做了.

    Note: System.copyof在 remove 方法中也是可以看到的.

          public void add(int index, E element) {
      rangeCheckForAdd(index);


      // Increments modCount!!
      ensureCapacityInternal(size + 1);
      System.arraycopy(elementData, index, elementData, index + 1,
      size - index);
      elementData[index] = element;
      size++;
      }







      好了,add方法看完了,那么我们来看get方法. 是怎么获取元素的.

      根据下标来获取值,再用下标获取值之前,会走一个下标是否越界的方法,如果越界的话,就会抛出异常来.

        public E get(int index) {
        rangeCheck(index);


        return elementData(index);
        }


        // 检查下标是否越界
        private void rangeCheck(int index) {
        if (index >= size)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        }

        // 获取值    
        E elementData(int index) {
        return (E) elementData[index];
        }



        好了, add/get都看完了,接着就看 set 方法.

        set方法是根据下标来进行赋值的

        第一步也是先检查下标是否越界了, 如果没越界就往下

        第二步获取之前的值,赋予一个新变量 oldValue

        第三步将下标对应的值替换为新值,最后返回旧值.

              public E set(int index, E element) {
          rangeCheck(index);


          E oldValue = elementData(index);
          elementData[index] = element;
          return oldValue;
          }



          最后, 到这里,其实我们使用的 ArrayList 的源码的工作原理,已经很大部分是可以理解的, ArrayList还是很好理解的.

          留下的 remove   isEmpty indexOf 等方法,大家也可以看看. 其代码理解起来,也不是很有难度.


                                                                          -- 这里是深文笔记.

                                                                          -- 交流技术vx :   l18776416225

           一起学习,一起进步.







          文章转载自深文笔记,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

          评论