这篇博客起源于我对Dictionary、List、ArrayList这几个类区别的好奇,当时在改造公司的旧系统,发现很多地方使用了ArrayList,但我们平时用的多是泛型集合List,改造的时候要全部替换成泛型集合,原本我对于这几个集合类就有些疑问,所以稍微做了些功课。
装箱与拆箱
在开始分析集合类之前先简单说下装箱拆箱的概念,在实际的开发中,也许我们很少提到这个概念,但它实际上遍布我们的开发过程,并且对性能有很大的影响,首先来了解一下什么是装箱和拆箱:
装箱和拆箱是值类型和引用类型之间相互转换是要执行的操作。
- 装箱在值类型向引用类型转换时发生
- 拆箱在引用类型向值类型转换时发生
int i = 123;
object o = (object)i; // 将int转object,发生装箱
int j = (int)o; // 从object转回原来的类型,解除装箱
通过上面的说明和例子可以看到,这是一个很简单的概念,实际上就是在我们进行类型转换时发生的一种情况,但如果我们再深入一些可以从数据结构的角度来更清晰地解释这个问题,先看下面两个例子:
值类型
int i = 123;
object o = i; // 装箱会把i的值拷贝到o
i = 456; // 改变i的值
// i的变化不会影响到o的值
Console.WriteLine("{0},{1}", i,o);
原始值类型和装箱的对象使用不同的内存位置,因此能够存储不同的值。
引用类型
public class ValueClass
{
public int value = 123;
public void Test()
{
ValueClass b = new ValueClass();
ValueClass a = b;
b.value = 456;
Console.WriteLine("{0},{1}", a.value, b.value);
}
}
两个变量指向同一块内存数据,当一个变量对内存区数据改变之后,另一个变量指向的数据当然也会改变。
简单地说,值类型的赋值相当于直接将物品交给另一个人,而引用类型的赋值相当于将一个存放了物品的地址复制给另一个人,每当有人来找的时候,再根据地址去找到物品,地址没有发生改变的情况下,将里面的物品替换,那么后面所有顺着线索找过来的人拿到的都是被替换的物品。如果以数据结构的知识来看,引用类型和值类型就是分别存放在堆和栈里面的数据。
堆与栈
我们把内存分为堆空间和栈空间:
- 线程堆栈:简称栈Stack,栈空间比较小&#