28

我最近遇到的另一个 C# 面试问题是我是否知道装箱和拆箱是什么。我解释了值类型在堆栈上,引用类型在堆上。当一个值被转换为引用类型时,我们称之为装箱,反之亦然。

然后他让我计算一下:

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

是什么i

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

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

我也期待看到b == 2,但事实并非如此,为什么?是不是因为第二次装箱破坏并替换a了堆上的整个对象?

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

public class TT
{
    public int x;
}

TT t = new TT();
t.x = 1;
TT t2 = new TT();
t2.x = 2;
t = t2;
t.x = 3;

是什么t2.x?它应该是 3,它是。但这根本不是装箱/拆箱的例子,对吗?那么你会如何总结这一点呢?

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

4

6 回答 6

8

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

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

于 2009-04-18T22:55:43.797 回答
5
  1. 你是对的,第二个任务取代了第一个。它不会更改装箱值。

  2. 您的示例没有使用拳击。值 (int) 存储为 int 而非装箱。

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

于 2009-04-18T21:12:45.197 回答
2

这是另一个支持 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
于 2012-07-12T18:24:38.003 回答
2

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

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

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

Point装箱时甚至不能更改可变结构。要访问结构的属性,您必须将其拆箱,因此您无法就地更改已装箱的结构。

于 2009-04-18T21:34:29.747 回答
1

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

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

于 2009-04-18T21:38:54.747 回答
0

我认为拆箱问题的答案是:拆箱转换的结果是一个临时变量(更多详细信息:链接)。

我认为您正在尝试做某事:

object a = new Point(10,10);
object b = new Point(20,20);
a = b;

((Point) b).X = 30; //after this operation also a.X should be 30

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

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

于 2009-04-18T22:27:13.770 回答