装箱拆箱

     偶今天看JDK5的时候也发现了装箱/拆箱概念,遂作一总结,以备后用。
     .net中有一个很重要的概念,装箱与拆箱,之后在jdk5也出现了自动装箱/拆箱的概念。偶对此表一下自己的理解。
一、什么时装箱/拆箱。
    这要涉及到数据类型,在.net中所有的类型都继承自System.Object,所有的类型都是对象.类型主要分为两种,一是值类型,包括原类型(Sbyte、Byte、Short、Ushort、Int、Uint、Long、Ulong、Char、Float、Double、Bool、Decimal)、枚举(enum)、结构(struct).另一类是引用类型,包括类、数组、接口、委托、字符串等.
    其中值类型是在栈中分配内存,本身的声明就是一个初始化的过程,其不需要进行垃圾回收,只要超出所定义的作用范围会自动释放内存.
    而引用类型则是在堆中分配的,和java一样,在堆种分配内存,而其托管堆进行垃圾回收.
当两种数据类型进行转换时就引出了装箱/拆箱.
    装箱:值类型到引用类型或到此值类型所实现的任何接口类型的隐式转换
            例如: int temp = 3;
                      System.Object obj = temp;
            其中,temp为值类型,在栈中分配;当分配obj这个引用类型时,我们需要在堆中分配一个obj对象,然后把temp值赋给它,这么一系列的过程就是装箱的过程。
    拆箱:从引用类型到任意值类型的显式转换。与装箱不同,拆箱式显示装换。
    例如:int temp = 3;
                System.Object obj = temp;
                int i = (int) obj;
            拆箱过程中,首先来确定对象obj为一个值类型的装箱值,然后把值赋给值类型。
     加个例子强化一下理解,西西
        int temp = 3;
      object obj = temp;
      Console.WriteLine (temp + "," + (int) obj);
      在此过程中,进行了3次装箱和1次拆箱;很明显,obj = temp时第一次装箱,temp + "," + (int) obj中,temp要先转换为String类,第2次装箱,(int)obj第3次装箱成引用类型。obj转换为int时拆箱。
二、评价装箱/拆箱。
    装箱和拆箱虽然满足了两只类型之间的转换。但是从装箱的过程中不难看出,每次装箱时要在堆中new一个新的对象,当量特别大是肯定会大大影响程序的效率。事物总有两面性,every sword has two sides,事情便简单了,性能也下来了。所以,在应用中,我们应该尽量避免装箱操作。
三、对装箱/拆箱更进一步的了解
    最后引用一个例子,摘自http://blog.csdn.net/tiger119/archive/2006/08/28/1134068.aspx
   装箱/拆箱并不如上面所讲那么简单明了,比如:装箱时,变为引用对象,会多出一个方法表指针,这会有何用处呢?
   我们可以通过示例来进一步探讨。
   举个例子。
   Struct A : ICloneable
   {
      public Int32 x;
      public override String ToString() {
         return String.Format("{0}",x);
      }
      public object Clone()   {
         return MemberwiseClone();
      }
   }
   static void main()
   {
     A a;
     a.x = 100;
     Console.WriteLine(a.ToString());
     Console.WriteLine(a.GetType());
     A a2 = (A)a.Clone();
     ICloneable c = a2;
     Ojbect o = c.Clone();
   }
   5.0:a.ToString()。编译器发现A重写了ToString方法,会直接调用ToString的指令。因为A是值类型,编译器不会出现多态行为。因此,直接调用,不装箱。(注:ToString是A的基类System.ValueType的方法)
   5.1: a.GetType(),GetType是继承于System.ValueType的方法,要调用它,需要一个方法表指针,于是a将被装箱,从而生成方法表指针,调用基类的System.ValueType。(补一句,所有的值类型都是继承于System.ValueType的)。
   5.2:a.Clone(),因为A实现了Clone方法,所以无需装箱。
   5.3:ICloneable转型:当a2为转为接口类型时,必须装箱,因为接口是一种引用类型。
   5.4:c.Clone()。无需装箱,在托管堆中对上一步已装箱的对象进行调用。
   附:其实上面的基于一个根本的原理,因为未装箱的值类型没有方法表指针,所以,不能通过值类型来调用其上继承的虚方法。另外,接口类型是一个引用类型。对此,我的理解,该方法表指针类似C++的虚函数表指针,它是用来实现引用对象的多态机制的重要依据。

你可能感兴趣的:(数据结构,C++,c,.net,C#)