美文网首页
2018-08-08

2018-08-08

作者: 大柚子_ | 来源:发表于2018-08-08 11:06 被阅读0次

    集合类的底层实现原理

    1、ArrayList底层实现和原理

    首先了解线性表、数组的概念。

    线性表:最基本、最简单、也是最常用的一种数据结构。线性表中数据元素之间的关系是一对一的关系,即除了第一个和最后一个数据元素之外,其它数据元素都是首尾相接的。线性表有两种存储方式。

    1)顺序存储结构

    2)链式存储结构

    数组,是一种典型的顺序存储结构。具有以下特点:

    1)是物理存储连续、逻辑存储连续的顺序表。

    2)利于查询。这种存储方式的优点是查询的时间复杂度为O(1),通过首地址和偏移量就可以直接访问到某元素。

    3)不利于修改。插入和删除的时间复杂度最坏能达到O(n),如果你在第一个位置插入一个元素,你需要把数组的每一个元素向后移动一位,如果你在第一个位置删除一个元素,你需要把数组的每一个元素向前移动一位。

    4)容量的固定性。就是当你不确定元素的数量时,你开的数组必须保证能够放下元素最大数量,遗憾的是如果实际数量比最大数量少很多时,你开的数组没有用到的内存就只能浪费掉了。

    ArrayList作为List的典型实现,完全实现了List的全部接口功能,它是基于数组实现的List类,它封装了一个Object[]类型的数组,长度可以动态的增长。如果在创建ArrayList时没有指定Object[]数组的长度,它默认创建一个长度为10的数组,当新添加的元素已经没有位置存放的时候,ArrayList就会自动进行扩容,扩容的长度为原来长度的1.5倍。它的线程是不安全的。扩容的本质其实就是创建一个容量更大的新数组,再将旧数组的元素复制到新数组当中去。

     ArrayList 增加改查其实本质就是操作数组

    添加操作

    ArrayList 的添加操作,也就是往其内部数组添加元素的过程。首先要确保就是数组有足够的空间来存放元素,因此也就有了扩容检测这一步骤。

    该操作可分为两种方式:指定位置(添加到数组指定位置)、不指定位置(添加到数组末尾)

    1)不指定位置时,则默认将新元素存放到数组的末尾位置。过程相对简单,这里不再分析。

    2)指定位置时,即将新元素存在到数组的指定位置。若该位置不是数组末尾(即该位置后面还存有元素),则需要将该位置及之后的元素后移一位,以腾出空间来存放新元素。

    修改方法

    修改方法,就是替换指定位置上的元素。原理相对简单,这里直接贴出源码。

    删除方法

    ArrayList 的删除操作同样存在两种方式:删除指定位置的元素、删除指定元素。后者相较于前者多了一个查询指定元素所处位置的过程。

    删除指定位置的元素时,需判断该位置是否在数组末尾,若是则将该位置的元素置空让 GC 自动回收;若不是,则需要将该位置之后的元素前移一位,覆盖掉该元素以到达删除的效果,同时需要清空末尾位置的元素。

    对于传入参数中包含索引的,都需要先进行索引合法性判断,如果合法直接返回index位置的元素。

    遍历方式

    List list =newArrayList<>() ;

    1)利用get方法获取

    for(int i = 0;i<list.size();i++){

            list.get(i);

    }

    2)利用迭代器进行遍历

    for (Iterator iter = list.iterator(); iter.hasNext(); ) {

        iter.next();

    }

    3)for (Object obj : list)

                ;

    4)list.forEach(

                    e->{

                        ;

                    }

            );

    在集合的数量非常小的情况的,一二三中的遍历速度没有显著的差别,但是随之数量的增加,第一中方式最快,第三种方法第二,第二种第三,第四种最慢。

    迭代器Iterator

    fast-fail快速失败机制

    Arrays.copy()和System.copy()

     通过源码不难看出,Arrays.copyOf()是依靠System.copyOf()方法来实现的。而System.copyOf()的方式被native关键字修饰,这说明它调用的是c++的底层函数,已经不是java的范围。 它们两者的主要是区别是,Arrays.copyOf()不仅仅是拷贝数组中的元素,在拷贝数组元组的时候会生成一个新的数组对象,但是System.copyOf()仅仅是拷贝数组中的元素。

    总结:

    1)ArrayList是基于数组实现的List类。会自动的进行扩容,采用Arrays.copyOf()实现

    2)如果在创建ArrayList时,可以知道ArrayList元素的数量最好指定初始容量,这样可以避免ArrayList的自动多次扩容问题。

    3)与 LinkedList 相比,ArrayList 适用于频繁查询的场景,而不适用于频繁修改的场景; 与 Vector 相比,ArrayList 的所有操作都是非线程安全的。

    4)线程不安全

    相关文章

      网友评论

          本文标题:2018-08-08

          本文链接:https://www.haomeiwen.com/subject/exetbftx.html