Array
和List
都属于顺序表。 因为Array 长度不可变,所以有了List。
存储结构
1、Array
Array是一段连续的存储结构
int[] array = new int[3]
array
其实记录的是数组的首地址,而array[1]
其实相当于在i的地址的基础上加上1个整数的地址偏移,然后再取这块地址中的值。
2、List
List
是不连续的存储结构,List
的每个节点都有着一个Next
属性,这个属性则记录着他的下一个节点的地址。
也就是说当我们想找第100个节点的时候,他还是需要从第一个节点,然后做99次Next操作,才能找到list[99]节点。
3、在查找一个元素时时分别生成以下IL码
Array:
IL_0020: ldloc.0
IL_0021: ldc.i4.3
IL_0022: ldelem.i4
IL_0023: stloc.2
List:
IL_0022: ldloc.0
IL_0023: ldc.i4.3
IL_0024: callvirt instance !0 class [mscorlib]System.Collections.Generic.List`1<int32>::get_Item(int32)
IL_0029: stloc.2
通过这两段IL,我们可以看到List
需要使用mscorlib
对List
的get_Item
方法。因为List是一个链表,所以我需要从第一个元素开始逐个Next到所需索引的元素。这是一个耗时的过程。
另外,CPU缓存会把一片连续的内存空间读入,因为数组结构是连续的内存地址,所以数组全部或者部分元素被连续存在CPU缓存里面,平均读取 每个元素的时间只要3个CPU时钟时间。而链表的节点分散在堆空间里面,这时候CPU缓存帮不上忙,只能是去读取内存,平均读取时间需要100个CPU时钟周期。 这样算下来,数组访问的速度比链表快33倍! (这里只是介绍概念,具体的数字因CPU而异)
空间扩展
数组必须要在初始化时分配固定的大小,比如说int[] a=new int[3];
如果我们仅仅写int[] a=new int[];
编译器就会无情地给我们报错。但是List
由于空间不必连续,所以无须指定初始大小。
存储内容
Array
数组可以包含基本类型和对象类型,
ArrayList
却只能包含对象类型。 但是需要注意的是:Array
数组在存放的时候一定是同种类型的元素。ArrayList
就不一定了,因为ArrayList
可以存储Object
。
适用场景
如果想要保存一些在整个程序运行期间都会存在而且不变的数据,我们可以将它们放进一个全局数组里,但是如果我们单纯只是想要以数组的形式保存数据,而不对数据进行增加等操作,只是方便我们进行查找的话,那么,我们就选择ArrayList。而且还有一个地方是必须知道的,就是如果我们需要对元素进行频繁的移动或删除,或者是处理的是超大量的数据,那么,使用ArrayList就真的不是一个好的选择,因为它的效率很低,使用数组进行这样的动作就很麻烦,那么,我们可以考虑选择LinkedList。
参考:
https://zhidao.baidu.com/question/2143832349386743788.html