• C#之装箱和拆箱


        在实际编码过程中,有时候会出现装箱和拆箱操作。下面就类分别认识一下:

    需要注意的是,类型转换和这个是不同的。Convert方法并没有发生装箱和拆箱操作,而是类型转换,包括int.parse等等。

    装箱,是把值类型拷贝了一个副本放在堆内存中。

    拆箱,在引用类型直接找到值类型存储的位置(Person对象是引用类型,但其Age属性是值类型,也存储在堆内存中),实际上我们往往拆箱后会用一个值类型变量接收它。

    例1:

    1             int n = 10;
    2             Console.WriteLine(n);
    3             object o = n;//一次装箱
    4             Console.WriteLine((int)o);
    5             Console.WriteLine(o);//这里输出的是字符串"10",相当于Console.WriteLine(o.ToString());

        上面的代码中,第2句话并没有发生装箱,因为Console.WriteLine()方法有一个int类型重载;第3句话发生一次装箱;而第4句话(int)o发生一次拆箱,拆箱后的值被其values接收,如果没有Console.WriteLine()方法有一个int类型重载的话,会马上再次装箱,因为这个重载,没有发生装箱;最后1句话,输出的是字符串"10",相当于Console.WriteLine(o.ToString())。所以在判断一句话是否发生装箱和拆箱要结合构造函数来看。

    例2:

    1             int n = 10;
    2 
    3             IComparable com = n;
    4 
    5             int m = (int)com;
    6 
    7             Console.WriteLine(m);

         上面的代码中,第二句话发生了装箱,第三句话发生了拆箱,因为int类型实现了IComparable接口。

    例3:

    1             int d = 999;
    2             object o = d; //装箱
    3 
    4             //装箱时使用什么类型,拆箱时也必须使用同样的类型。否则报异常
    5             double d1 = (double)o; //拆箱 
    6 Console.WriteLine(d1);

    例3中,编译会报错,以为在第2句话装箱前是int类型,而拆箱时确是double。需要注意的是,装箱前是什么类型,拆箱后也必须是什么类型,否则会报错

    例4:

     1            int n = 100;
     2             M1(n);
     3 
     4             string x = "a";
     5             double d1 = 10;
     6             string y = "b";
     7             int n1 = 9;
     8             string z = "c";
     9             string full = x + d1 + y + n1 + z;
    10             Console.WriteLine(full);
    11 
    12        //定义函数如下:
    13         static void M1(double d)
    14         {
    15             Console.WriteLine(d);
    16         }
    17 
    18         static void M1(object o)
    19         {
    20             Console.WriteLine(o);
    21         }

    上面的代码到底发生了几次装箱和拆箱呢?首先看M1()方法,经反编译得知M1((double) n);由此可见,M1()方法并没有去找object类型的重载,而是找了与之相近的double类型重载,所以没有发生装箱。第9句话经反编译得知Console.WriteLine(string.Concat(new object[] { x, d1, y, n1, z }));它将double类型变量d1和int类型变量n1装箱成object类型。所以上面的代码只发生了2次装箱。

    装箱和拆箱带来的性能影响:

    日常编码中应避免装箱和拆箱,因为他们会带来性能的损耗。看下面的代码:

    1             ArrayList aList = new ArrayList();
    2             Stopwatch sw = new Stopwatch();
    3             sw.Start();
    4             for (int i = 0; i < 100000; i++)
    5             {
    6                 aList.Add(i);   //Add方法每添加一次发生一次装箱
    7             }
    8             sw.Stop();
    9             Console.WriteLine("用时:"+sw.Elapsed);

    运行结果:

    我们换另一种:

    1             List<int> aList = new List<int>();
    2             Stopwatch sw = new Stopwatch();
    3             sw.Start();
    4             for (int i = 0; i < 100000; i++)
    5             {
    6                 aList.Add(i);   
    7             }
    8             sw.Stop();
    9             Console.WriteLine("用时:" + sw.Elapsed);

    运行结果:

    由此可见,性能影响还是挺大的。

    总结:

    一)装箱和拆箱的判断依据:
    1.发生在值类型和引用类型之间;
    2.具备父子类的关系。

    二)判断一句话是否发生装箱和拆箱要结合构造函数来看;

    三)装箱前是什么类型,拆箱后也必须是什么类型,否则会报错;

    四)写代码的过程中应尽量避免装箱和拆箱带来的性能消耗。

  • 相关阅读:
    JS BOM对象 History对象 Location对象
    JS 字符串对象 数组对象 函数对象 函数作用域
    JS 引入方式 基本数据类型 运算符 控制语句 循环 异常
    Pycharm Html CSS JS 快捷方式创建元素
    CSS 内外边距 float positio属性
    CSS 颜色 字体 背景 文本 边框 列表 display属性
    【Android】RxJava的使用(三)转换——map、flatMap
    【Android】RxJava的使用(二)Action
    【Android】RxJava的使用(一)基本用法
    【Android】Retrofit 2.0 的使用
  • 原文地址:https://www.cnblogs.com/chens2865/p/3858162.html
Copyright © 2020-2023  润新知