java ArrayList 概述 与源码简析

ArrayList 概述 与源码简析

1 ArrayList 创建
ArrayList<String> list = new ArrayList<>();
//构造一个初始容量为10 的空列表 
  • 源码分析 当我们使用上面的构造来创建ArrayList的时候,其实其实内部是创建了一个 Object[] 空的数组

 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

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


2 ArrayList 添加数据


添加单个数据

    //添加数据
    arrayList.add("afd");
    arrayList.add("afd");
    arrayList.add("afd");

    System.out.println(arrayList);//[afd, afd, afd]

    /**
     * 向ArrayList中的0号位置上 添数据 
     * 通过这个方法添加数据,位置限定在  0 到 arraylist.size()中
     */
    arrayList.add(0,"qq");

    System.out.println(arrayList);//[qq, afd, afd, afd]


  • arrayList.add(0,”qq”);
    • 源码中 首先调用了 rangeCheckForAdd(index);方法来检察 传入的角标的范围,不在范围内就抛出异常
    • 而最终是通过 Arrays.copyOf(elementData, newCapacity)这个方法将原来集合中的内容copy到新的集合中去


    //add方法的源码
    public void add(int index, E element) {
        rangeCheckForAdd(index);

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

    //方法来检察 传入的角标的范围,不在范围内就抛出异常 
     private void rangeCheckForAdd(int index) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }


添加集合中的数据


    ArrayList<Integer> arrayList2 = new ArrayList<Integer>();

    arrayList2.add(1);

    ArrayList<Integer> arrayList3 = new ArrayList<Integer>();

    arrayList3.add(3);
    //将 arraylist2 中的数据全部添加到arraylist3集合中
    arrayList3.addAll(arrayList2);

    System.out.println(arrayList3);//[3, 1]


  • 分析其源码我们会发现,其先是通过 toArray()方法将集合数据转为数组数据, 最终是通过 System.arraycopy()方法 数据copy到了一个新的数组中
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;
    }


3 ArrayList 移除集合中的所有的数据



    ArrayList<String> arrayList = new ArrayList<String>();

    //添加数据
    arrayList.add("afd");
    arrayList.add("afd");
    arrayList.add("afd");

    System.out.println(arrayList);//[afd, afd, afd]
    //移除集合中的所有的数据 
    arrayList.clear();
    System.out.println(arrayList);//[]


  • 分析其源码我们会发现, 其实是将 集合底层保存数据的数组中的元素设置为了 null , 同时将记录元素个数的变量size的值置为0


//clear功能源码 
public void clear() {
        modCount++;

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

        size = 0;
}


4 ArrayList 判断是否包含指定的元素


4.1 判断操作


    ArrayList<String> arrayList = new ArrayList<String>();
    //添加数据
    arrayList.add("afd");
    arrayList.add("afd");
    arrayList.add("afd");

    //判断 集合中是否包含指定的元素 ,饱含返回true ,不包含返回false 
    boolean contains = arrayList.contains("afd");

    System.out.println(contains);//true


4.2 源码分析

public boolean contains(Object o) {
        return indexOf(o) >= 0;
 }
可以发现其内部是调用了indexOf()方法,该方法去数组中查询指定的元素在其中第一次出现的位置 ,如果没有就返回-1,如果有就返回该位置 


5 ArrayList 判断列表中是否有元素(是否不为空)


//集合为空 返回true 不为空返回false 
boolean empty = arrayList.isEmpty();

源码分析

//这里的size 是集合对应的保存数据的内容数组的大小
public boolean isEmpty() {
        return size == 0;
}


6 ArrayList 移除元素



    ArrayList<String> arrayList = new ArrayList<String>();
    //添加数据
    arrayList.add("afd");
    arrayList.add("abc");
    arrayList.add("axc");

    //方式一 移除0角标的数据
    arrayList.remove(0);
    System.out.println(arrayList);//[abc, axc]
    //方式二 移除数据 "axc"
    arrayList.remove("axc");
    System.out.println(arrayList);//[abc]



源码分析


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

        modCount++;
        E oldValue = elementData(index);

        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

        return oldValue;
}

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;
    }
这是两个重载的方法 remove(int index) 是根据传入的角标,根据角标去除对应的数据,最后还是通过System.arraycopy方法来重建新的数组

remove(Object o) 是直接移除元素的方法,元素有可能为 null,所以这里有了一个判断 ,最终都是通过 fastRemove(index);方法中的System.arraycopy逻辑来创建新的数组的


7 ArrayList 修改数据



    ArrayList<Integer> arrayList = new ArrayList<Integer>();
    //添加数据
    for (int i = 0; i <14; i++) {
        arrayList.add(i);
    }
    System.out.println(arrayList);//[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]

    //修改数据  修改0 号位置上的数据为100
    Integer set = arrayList.set(0, 100);
    System.out.println(arrayList);//[100, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]


源码分析

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

        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;
}
private void rangeCheck(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
  • 先通过 rangeCheck(index) 方法来检验修改数据传入的角标值是否有效
  • 然后通过elementData(index) 拿到数组中对应角标的数据,并返回去
  • 最后重新对数组中对应角标下进行赋值


8 ArrayList 获取集合中元素的个数



    ArrayList<Integer> arrayList = new ArrayList<Integer>();
    //添加数据
    for (int i = 0; i <14; i++) {
        arrayList.add(i);
    }
    System.out.println(arrayList);//[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]

    //获取集合中元素的个数 
    int size = arrayList.size();
    System.out.println(size);//14

源码分析

public int size() {
        return size;
    }
源码中 直接将记录 元素个数变化的变量size的值返回去


9 ArrayList 转为对应的数组



ArrayList<Integer> arrayList = new ArrayList<Integer>();
    //添加数据
    for (int i = 0; i <14; i++) {
        arrayList.add(i);
    }
    System.out.println(arrayList);//[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]

    //操作方式一 
    Object[] objArray= arrayList.toArray();
    for (int i = 0; i < objArray.length; i++) {
        //取出数据 
        Integer num = (Integer) objArray[i];
        System.out.println(num);
    }

    //操作方式二
    //创建将要保存数据的 数组 
    Integer[] array = new Integer[arrayList.size()];
    //将集合中的数据转存到数组中 
    arrayList.toArray(array);
  • 操作方式一中 ,通过toArray()方法是一个Object对象数组,可以在每次取出数据的时候,将数组类型强转

源码分析


public Object[] toArray() {
        return Arrays.copyOf(elementData, size);
}
  • toArray() 方法是直接使用了 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;
}
  • toArray(T[] a)方法中 当目标数组长度小于集合元素个数的时候,通过 Arrays.copyOf () 来构建赋值数组,否则的话就会通过 System.arraycopy()方法拷贝数组
早起的年轻人 CSDN认证博客专家 移动开发 项目管理 Java
只要用心去做,每一件事情还是有可能成功的,当然成功是没有界限的,只不过是达到自己心里的那个目标,公众号:我的大前端生涯,一个爱喝茶的程序员,通常会搞搞SpringBoot 、Herbinate、Mybatiys、Android、iOS、Flutter、Vue、小程序等.
©️2020 CSDN 皮肤主题: 代码科技 设计师:Amelia_0503 返回首页