zoukankan      html  css  js  c++  java
  • 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.具备父子类的关系。

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

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

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

  • 相关阅读:
    J Identical Trees(求俩个树转化所需的最小代价,hash判同构,费用流求转移代价)
    I Tournament(俩人一组,构造最少排队总时间)
    D
    purfer序列(有关度数与生成树个数情况)
    博客园自定义样式
    莫比乌斯知识点整理
    随笔日记
    牛客小白月赛16
    Codeforces Round #555 (Div. 3)
    Codeforces Round #553 (Div. 2)
  • 原文地址:https://www.cnblogs.com/chens2865/p/3858162.html
Copyright © 2011-2022 走看看