2018-08-08

2018-08-08  本文已影响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)线程不安全

上一篇下一篇

猜你喜欢

热点阅读