首先,如果听起来太愚蠢,我道歉。但我总是发现自己提出以下问题。
由于对象类是.Net中所有类的最终基类,而类是引用类型,引用类型存储在堆上,因此甚至可以进入堆栈。 我知道原始类型存储在堆栈中,这就是我感到困惑的地方。
以int32为例,如果它的一个类及其基类是object,那么它的引用类型应该在堆上。怎么去堆叠。
如果它不是一个类,那我们怎么做呢
int i = 1;
object obj = i;
因为我不能做像
这样的事情int i = 1;
MyClass myObj = i;
修改
从我得到的答案来看,int是结构而不是类。仍然令人困惑的是值类型的基类是如何引用类型(对象)而它的值类型不是引用类型。
另一个观点是“属于类的值类型不会存储在堆栈中”,我想一切都在类中,甚至是控制台程序中的Main方法。对我来说,这意味着所有变量都以某种方式属于一个类?那他们怎么去堆叠?
答案 0 :(得分:14)
首先,如果听起来太愚蠢,我道歉。但我总是发现自己提出以下问题。
这些是非常常见的问题。
由于对象类是.Net中所有类的最终基类,而类是引用类型,引用类型存储在堆上,因此甚至可以进入堆栈。
你很困惑很多事情。让我们从:
开始好的,现在我们知道有三种东西,其中两种是价值。
现在让我们正确陈述你的句子:
对象类是.NET中所有类的最终基类。类的所有实例都是引用类型的实例。引用类型的所有实例都存储在堆上。如何将任何内容存储在堆栈中?
既然我们正确地提出了问题,答案很明确。 引用和值类型的实例可以进入堆栈。
让我们继续前进。
我知道原始类型存储在堆栈中,这就是我感到困惑的地方。
从你的词汇中消除“原始类型”这个词;这毫无意义。让我们改写一下:
我知道值类型的实例存储在堆栈
上
不,您不知道,因为为了算作知识,语句必须为true。那句话是错误的。值存储在变量中。变量要么是长寿命的,要么是短命的。短期变量在堆栈上。长期存在的变量就在堆上了。
以int32为例,如果它的一个类及其基类是object,那么它的引用类型应该在堆上。
Int32不是一个类。这是一个结构。它不是参考类型。
玛丽是个母亲。她是女性。因此,她的孩子都是女性吗?值得注意的仍然是值类型的基类是引用类型(对象),而值类型不是引用类型。
如何进行堆叠。
当整数存储在一个短期变量中时,整数会进入堆栈。
当引用存储在一个短期变量中时,引用会进入堆栈。
值是引用还是值类型的实例是无关紧要的;重要的是变量存活多长时间?
如果它不是一个类,那我们怎么做呢
int i = 1;
object obj = i;
好问题。生成一个特殊类。把它想象成:
class BoxedInt
{
int value;
public BoxedInt(int v) { this.value = v; }
public int Unbox() { return this.value; }
}
那么你的程序片段就是:
int i = 1;
object obj = new BoxedInt(i);
然后
int j = (int)obj;
与
相同int j = ((BoxedInt)obj).Unbox();
提出的另一点是“属于某个类的值类型不会存储在堆栈中
更好的说法是:引用类型的字段是长期存在的变量。因此它们存储在堆上。
我猜一切都在一个类中,甚至是控制台程序中的Main方法。
是的,所有代码都在类或结构中。
对我来说,这意味着所有变量都以某种方式属于一个类?
不,本地变量不是类的成员。
我住在一个黄色的房子里。因此,它内部的所有物体都是黄色的吗?那他们怎么去堆叠?
普通方法中的局部变量是短暂的,因此它会进入堆栈。
只需停止将堆栈视为与存储的数据类型有关。 堆栈与存储的数据类型无关。考虑变量。堆栈是短期变量的地方。堆是长寿命变量的地方。变量的类型无关紧要。
答案 1 :(得分:1)
Int32
不是一个类。它是struct
。structs
由编译器专门处理。
object obj = i;
这称为拳击。因为所有类都是从对象隐式继承的,所以你可以为object分配任何东西。你应该看看documentation这个,还有成千上万的关于装箱和拆箱的文章。
来自MSDN:
Boxing是将值类型转换为类型对象或由此值类型实现的任何接口类型的过程。当CLR选择一个值类型时,它将值包装在System.Object中并将其存储在托管堆上。
以下是一些可能有用的参考资料
答案 2 :(得分:1)
Int32
是一个ValueType,因此它将在堆栈中分配。关键字int
引用结构System.Int32
。
.net中的类型分为value types
和reference types
。
值类型是堆栈分配或在结构中内联分配。
引用类型是堆分配。
价值类型包括两个主要类别:
引用和值类型都是从最终基类Object
派生的。
如果值类型的行为必须像 object,一个使值类型看起来像引用的包装器 对象在堆上分配,并复制值类型的值 进去。包装器已标记,因此系统知道它包含a 值类型。这个过程称为拳击,反向过程 被称为拆箱。
参考here
答案 3 :(得分:0)
原始数据类型是值类型,它们的大小是在编译时定义的,因此编译器将它们推送到堆栈以便更快地访问,而引用类型只是指向存储在堆上的对象的起始地址的指针,并且它的内存未在编译时分配时间(在运行时分配)。
你做不到
int i = null; // Because it's value type and need some value
(Default is 0) here int is alias to Int32 which is structure and
structure is value type and same is for other primitives
答案 4 :(得分:0)
System.Object
不是“类”,但类型System.Object
的实例是引用类型。B
继承自A
类型,则隐含的仅事件是B
获取所有A
个{ {1}}或public
非静态方法,属性和事件。基本上,值类型在内存中可以有两种不同的表示形式(盒装和非盒装),而引用类型在内存中只有一种表示形式。
首先,你绝对可以这样做:
protected
只需将int i = 1;
MyClass myObj = i;
定义为:
MyClass
(请注意,在此示例中,类class MyClass
{
int i;
public MyClass(int i)
{
this.i = i;
}
public static implicit operator MyClass(int i)
{
return new MyClass(i);
}
}
的字段i
是堆分配的 ,即使它是值类型)
其次,值类型不一定存储在堆栈中,如下例所示:
MyClass
现在,当类型class
继承自B
类型时,这意味着仅 A
获取所有B
的{{1} },A
和properties
。它没有规定如何分配methods
的实例。