Array 与ArrayList 与List 的前世今生
2018-12-15 本文已影响7人
迷糊银儿
一、既生瑜(Array)何生亮(ArrayList)
- 数组优点
数组在内存中是连续存储的,所以它的索引速度非常之快,而且赋值与修改元素也很简单。 - 数组缺点
- 数组在声明的时候必须说明它所存储的元素类型与数组的长度,数组的长度过长,会造成内存浪费,数组和长度过短,会造成数据溢出的错误。
- 数组在插入、删除元素应用场景下的效率确实差强人意。
基于上述数组的缺点,ArrayList登上历史舞台,Array的缺点也自然而然成了ArrayList的优点
二、ArrayList
- ArrayList优点
在声明ArrayList的时候并不需要声明它的长度与存储的元素类型。秘密在这里:- 容量可动态增长
- ArrayList存入对象时,抛弃类型信息,所有对象屏蔽为Object,编译时不检查类型,但是运行时会报错。
- ArrayList缺点
数组扩容是对ArrayList效率影响比较大的一个因素。
每当执行Add、AddRange、Insert、InsertRange等添加元素的方法,都会检查内部数组的容量是否不够了,如果是,它就会以当前容量的两倍来重新构建一个数组,将旧元素Copy到新数组中,然后丢弃旧数组,在这个临界点的扩容操作,应该来说是比较影响效率的。
使用建议
基于效率和类型检验,应尽可能使用Array,无法确定数组大小时才使用ArrayList!
三、关List什么事
- ArrayList的硬伤
- 我们往ArrayList中插入"abc"与123是没有问题的,因为ArrayList把所有插入其中的元素都当作object类型来处理。这样,在我们使用ArrayList中的数据来处理问题的时候,很可能会报类型不匹配的错误,也就是说ArrayList不是类型安全的。
- 我们保证在插入数据的时候都很小心,都有插入了同一类型的数据,但在使用的时候,我们也需要将它们转化为对应的原类型来处理。这就存在了装箱与拆箱的操作,会带来很大的性能损耗。
装箱与拆箱的概念: 装箱:就是将值类型的数据打包到引用类型的实例中 比如将int类型的值123赋给object对象
int i=123; object o=(object)i;
拆箱:就是从引用数据中提取值类型 比如将object对象o的值赋给int类型的变量 object o=123; int i=(int)o;
装箱与拆箱的过程是很损耗性能的。
基于上述ArrayList的硬伤,又出现了范型的概念。而而List类是ArrayList类的泛型等效类。
四、 List
它的大部分用法都与ArrayList相似,最关键的区别在于,在声明List集合时,我们同时需要为其声明List集合内数据的对象类型。
List<int> list = new List<int>();
//新增数据
list.Add(123);
//修改数据
list[0] = 345;
//移除数据
list.RemoveAt(0);
如果我们往List集合中插入string字符"hello world",IDE就会报错,且不能通过编译。这样就避免了前面讲的类型安全问题与装箱拆箱的性能问题了。
- List不能被构造,但可以向上面那样为List创建一个引用,而ListArray就可以被构造。
List list; //正确 list=null;
List list=new List(); // 是错误的用法
List<int> list = new ArrayList();这句创建了一个ArrayList的对象后把上溯到了List。此时它是一个List对象了,有些ArrayList有但是List没有的属性和方法,它就不能再用了。 而ArrayList list=new ArrayList();创建一对象则保留了ArrayList的所有属性。
- List泛型的好处:
通过允许指定泛型类或方法操作的特定类型,泛型功能将类型安全的任务从您转移给了编译器。不需要编写代码来检测数据类型是否正确,因为会在编译时强制使用正确的数据类型。减少了类型强制转换的需要和运行时错误的可能性。泛型提供了类型安全但没有增加多个实现的开销。