快捷搜索:  汽车  科技

装箱和拆箱示例(C-)

装箱和拆箱示例(C-)////1 同是引用类型 ////将子类赋值给父类 //Person p = new Student(); ////这个是进行了显示类型转换 不叫拆箱 //Student stu = (Student)p; ////原因在于它们都是引用类型 因此 ////只存在类型转换的关系 ////int类型为什么可以装箱到object类型 ////但不能装箱到string类型或Person类型 ////原因在于:object类型是int类型的父类(值类型也继承自object) //2 通过方法将值类型转换为引用类型 int n = 10; //不是装箱 只是进行了隐式类型转换 string s1 = Convert.Tostring(n); //不是拆箱 只是进行了隐式类型转换 //只是从意义上而不是从内存上进行转换 int m = int.Parse(s1); //原因在

1)了解装箱拆箱的概念

2)掌握什么情况下会发生装箱 拆箱操作(2-7)

3)通过示例查看有无装箱拆箱操作的性能差别(查看消耗时间)

装箱拆箱的定义:

1) 装箱:将值类型转换为引用类型 是隐式进行的

2) 拆箱:将引用类型转换为值类型 是显示进行的

因为每进行一次装箱或拆箱操作都会涉及一次内存的拷贝动作 因此大量频繁地进行装箱拆箱的操作会大幅影响程序的性能

标准装箱拆箱

在C#中object类型是所有类型的基类 因此值类型 引用类型都可以赋值给object类型

//声明了值类型 n int n = 8; //进行了装箱操作 //将值类型 n 进行了隐式(自动)转换 //将其赋值给了引用类型的 o object o = n; //进行拆箱操作 //将引用类型的 o 进行了显示(强制)转换 //将其赋值给了 值类型的 m int m = (int)o; Console.WriteLine(m); Console.ReadKey();

装箱和拆箱示例(C-)(1)

反编译查看底层的装箱拆箱操作

只进行类型转换而无装箱拆箱

////1 同是引用类型 ////将子类赋值给父类 //Person p = new Student(); ////这个是进行了显示类型转换 不叫拆箱 //Student stu = (Student)p; ////原因在于它们都是引用类型 因此 ////只存在类型转换的关系 ////int类型为什么可以装箱到object类型 ////但不能装箱到string类型或Person类型 ////原因在于:object类型是int类型的父类(值类型也继承自object) //2 通过方法将值类型转换为引用类型 int n = 10; //不是装箱 只是进行了隐式类型转换 string s1 = Convert.Tostring(n); //不是拆箱 只是进行了隐式类型转换 //只是从意义上而不是从内存上进行转换 int m = int.Parse(s1); //原因在于:字符串类型与int类型在内存上不存在"交集" //根本无法进行类型转换 而object与int可以转换的原因是 //因为任何类型都是继承自object类型 可反编译在IL模式下查看是否有 box与unbox操作拆箱时 必须使用装箱时的类型来拆箱

装箱的时候 使用什么类型来装箱 拆箱的时候还必须使用原来的类型来拆箱 否则会报异常:指定的转换无效

装箱和拆箱示例(C-)(2)

使用原类型进行拆箱操作

int n = 10; object obj = n; //进行了装箱 double d = (int)obj;//进行了拆箱 //只要保证拆箱的类型与装箱时的类型一样即可 //最后赋值给 double 的 d 只是进行了隐式类型转换 //与装箱拆箱操作无关 Console.WriteLine(d); //============================ //无法进行拆箱 会报异常:指定的转换无效 //装箱时类型为 int 拆箱时类型为 double double f = (double)obj; Console.WriteLine(f); Console.ReadKey();方法重载时 参数有该类型的重载 不叫装箱拆箱

int n = 10; //只是进行了类型转换 //没有发生装箱操作 string m = n.ToString(); //没有发生拆箱操作 int num = Convert.ToInt32(m); Console.WriteLine(num); Console.ReadKey();接口与值类型之间的装箱与拆箱

值类型也可以继承接口 如int32实现(继承的意思)了3个接口与两个泛型接口

int n = 8; //进行了装箱操作 IComparable ic = n; //进行拆箱操作 int m1 = (int)ic;//拆箱后赋值给了原类型变量 //拆箱后先进行了隐式类型转换 //然后赋值给了float类型的变量 float m2 = (int)ic; Console.WriteLine(m1 " " m2); Console.ReadKey();进行字符串连接时也会发生装箱 拆箱操作

string s1 = "a"; string s2 = "b"; int n3 = 10;//装箱 float n4 = 9.9f;//装箱 double n5 = 99.9;//装箱 //Concat()将参数进行连接 //共进行了3次装箱操作 string result = string.Concat(s1 s2 n3 n4 n5); Console.WriteLine(result); Console.ReadKey();

装箱和拆箱示例(C-)(3)

字符串连接会发生装箱操作

装箱拆箱消耗性能问题

通过向ArrayList与List集合中添加10万个数字查看有无装箱时消耗时间的差别

//声明时就设置好容量 可节省性能 int capacity = 1000000; ArrayList arList = new ArrayList(capacity); List<int> list = new List<int>(capacity); Console.WriteLine("共进行 {0} 次的添加元素" capacity); Console.WriteLine("ArrayList集合 会发生装箱操作"); Stopwatch sw = new Stopwatch(); sw.Start();//开始计时 for (int i = 0; i < capacity; i ) { arList.Add(i); } sw.Stop(); Console.WriteLine("共消耗 {0} 毫秒" sw.ElapsedMilliseconds); Console.WriteLine(""); Console.WriteLine("List泛型集合 不会发生装箱操作"); sw.Reset();//重置对象 //sw.Restart();//重启对象 sw.Start();//开始计时 for (int i = 0; i < capacity; i ) { list.Add(i); } sw.Stop(); Console.WriteLine("共消耗 {0} 毫秒" sw.ElapsedMilliseconds); Console.ReadKey();

装箱和拆箱示例(C-)(4)

两种集合所耗时间

使用集合时 尽量使用泛型集合 以减少操作时中间可能存在的消耗

小结:

1)装箱拆箱(以下以"此操作"代指)发生在引用类型与值类型之间

2)即使是值类型与引用类型如果转换方法有该类型作为参数 也不会发生此操作

3)接口与值类型 字符串连接上都会发生此操作

猜您喜欢: