拆箱和装箱
例:Integer是一个封装类,用于表示整数。它是int的封装类,可以将int类型的数据转换为Integer类型的数据。Integer类提供了许多操作整数的方法,使得整数的操作更加方便和灵活。
int是基本数据类型,而Integer是int的封装类。
int类型的数据直接存储在内存中的栈中,而Integer类型的数据则存储在堆中的对象中。
装箱:
对值类型在堆中分配一个对象实例,并将该值复制到新的对象中。按三步进行。
1:首先从托管堆中为新生成的引用对象分配内存(大小为值类型实例大小加上一个方法表指针和一个SyncBlockIndex)。
2:然后将值类型的数据拷贝到刚刚分配的内存中。
3:返回托管堆中新分配对象的地址。这个地址就是一个指向对象的引用了。
可以看出,进行一次装箱要进行分配内存和拷贝数据这两项比较影响性能的操作。
拆箱:
1、首先获取托管堆中属于值类型那部分字段的地址,这一步是严格意义上的拆箱。
2、将地址的值拷贝到位于线程堆栈上的值类型实例中。
装箱比较耗费性能
ArrayList和List之间的区别以及相互转换方法
ArrayList:需要先将类型转变为Object,再将Object转换为其所对应的类型。有个先装箱,再拆箱的过程。
List:泛型中指定了类型,其不需要进行装箱拆箱,效率也就相对提升。
List和ArrayList的区别
1.list性能较高,ArrayList性能较低
2.list一次存储中只能存储泛型中的类型,ArrayList在一次存储中任何类型的数据
3.List中获取值取出的是泛型中发的类型,因为ArrayList对元素没有限制,系统会将中获取的值当object类型的数据
4.List属于泛型集合 ArrayList属于非泛型集合
如果想获取到其中的内容需要进行
List在使用时候需要导入的using指令为using System.Collections.Generic;
ArrayList在使用的时候需要导入的using指令为using System.Collections;
浅拷贝和深拷贝
浅拷贝: 仅仅把对象的引用进行拷贝,但是拷贝对象和源对象还是引用同一份实体。此时,其中一个的成员对象的改变都会影响到另一个的成员对象。
深拷贝:指的是拷贝一个对象时,不仅仅把对象的引用进行拷贝,还把该对象引用的值也一起拷贝。这样进行深拷贝后的副本对象就和源对象互相独立,其中任何一个的成员对象改动都不会对另外一个成员对象造成影响。
都发生了改变,浅拷贝
//a.CopyTo(b, 1);//就是把b中的值拷贝给aArray,实现深拷贝。
b长度要大于a//index含义是b开始存储拷贝数据的下标
深拷贝
equals和==
对于值类型
在C#中对于值类型的比较不管是用【==】还是【equals】都是对于其内容的比较,也就是说对于其值的比较,相等则返回true 不相等则返回false;
对于引用类型
对于除string类型以外的引用类型
【==】比较的是在对象在栈上的引用是否相同而【equals】则比较的是对象在堆上的内容是否相同
对于字符串类型
-
//常量字符串
-
string x = "should it matter"; //指向同一个地址,即所谓的常量池
-
string y = "should it matter";
-
object c = x;
-
object d = y;
-
Console.WriteLine(c == d);//输出True
-
Console.WriteLine(c.Equals(d));//输出True
-
//字符串变量
-
String str1=newString("aa");;//指向的地址不一样,是动态分配的
-
String str1=newString("aa");
-
object g = a;
-
object h = b;
-
Console.WriteLine(g == h);//输出False地址不同
-
Console.WriteLine(g.Equals(h));//输出True内容相同
-
string类型的内存分配
string sutdent1="刘德华";//"刘德华"在堆上string student2=sutdent1;//stu2=1的地址也指向2
当修改stu2的值stu1的值不会改变
这是因为string字符串的不可变性造成的。一个string变量一旦声明并初始化以后,其在堆上面分配的值就不会改变了。这时修改student2的值,并不会去修改堆上面分配的值,而是重新在堆上面开辟一块内存来存放student2修改后的值。