拳击与拆箱

我最近的另一个C#面试问题是,如果我知道Boxing和Unboxing是什么。 我解释了堆上的值类型和Heap上的引用类型。 当一个值转换为引用类型时,我们将其称为装箱,反之亦然。

然后他让我算一算:

int i = 20; object j = i; j = 50; 

我是什么人?

我把它搞砸了,并说50,其实际为20.现在我想明白为什么,但是当我玩不同的组合时,我很惊讶地看到这个:

 Object a = 1; // Boxing Object b = a; // referencing the pointer on stack to both objects on heap a = 2; // Boxing 

我期待看到b == 2 ,但事实并非如此,为什么? 是因为第二次拳击会破坏并替换堆上的整个对象吗?

因为如果我这样做,那很好:

 public class TT { public int x; } TT t = new TT(); tx = 1; TT t2 = new TT(); t2.x = 2; t = t2; tx = 3; 

什么是t2.x ? 它应该是3,它是。 但这不是拳击/拆箱的一个例子,这是正确的吗? 那你怎么总结这个呢?

这些值在上面的装箱/拆箱转换中是否会变得相同?

  1. 你是对的,第二个任务取代了第一个。 它不会更改盒装值。

  2. 你的例子没有使用拳击。 值(int)存储为int而不是boxed。

  3. 不,拳击仍然保持不变性保证。

非常简短:装箱意味着创建一个引用类型的新实例 。 如果你知道这一点,你就会明白一个实例不会因创建另一个实例而改变。

使用a = 2操作不会更改“框”中的值,而是创建引用类型的新实例。 那么为什么还要改变呢?

我期待看到b == 2,但事实并非如此,为什么? 是因为第二次拳击会破坏并替换堆上的整个(a)对象?

不,不完全是。 它将对象保留在堆上(因为b变量也引用它)并为新值创建一个新对象,变量将引用该对象。

你是对的,你的第二个例子不使用拳击。 除了取消装箱之外,您无法访问以其他任何方式装箱的值,因此无法更改装箱值。

当装箱时,甚至不能像Point那样改变可变结构。 要访问结构的属性,必须将其取消装箱,这样就无法更改盒装结构。

这是支持Stefan评论的另一个有趣变体:

  int i = 2; object a = i; // Boxing object b = a; // Referencing same address on heap as 'a', b == a b = i; // New boxing on heap with reference new address, b != a 

b仍然是1,因为b是仍然指向堆上的对象的引用,其值为1.a为2,因为您将其分配给堆上的新对象,值为2。

t2.x是3,因为t和t2是对堆上同一对象的两个不同引用。

我认为解包问题的答案是:取消装箱转换的结果是一个临时变量(更多细节: 链接 )。

我想你想做的事情如下:

 object a = new Point(10,10); object b = new Point(20,20); a = b; ((Point) b).X = 30; //after this operation also aX should be 30 

上面的代码将无法编译 – 上面链接中的详细信息,我认为这是您的问题的答案:

我期待看到b == 2,但事实并非如此,为什么? 是因为第二次拳击会破坏并替换堆上的整个(a)对象?