最近在看.NET中栈和堆的比较系列的技术文章,对于栈和堆的我还是个初学者
在学习过程中,有点疑问,请大虾们参考下~
首先下面是文章里的原话:
1. 引用类型总是放在堆中。(够简单的吧?)
2. 值类型和指针总是放在它们被声明的地方。(这条稍微复杂点,需要知道栈是如何工作的,然后才能断定是在哪儿被声明的。) 然后他举例说明
假如我们执行以下的方法:
第一个例子
public int ReturnValue()
{
int x = new int();
x = 3;
int y = new int();
y = x;
y = 4;
return x;
}第二个例子
假如我们首先使用MyInt类
public class MyInt
{
public int MyValue;
}
接着执行以下的方法:
public int ReturnValue2()
{
MyInt x = new MyInt();
x.MyValue = 3;
MyInt y = new MyInt();
y = x;
y.MyValue = 4;
return x.MyValue;
}以上的他讲的是很清楚,我也明白。但是有一个小小的疑问
public class MyInt
{
public int MyValue;
}
这段代码按照开头那2句话和图解,MyInt是个类也就是引用类型,理所当然是放置在堆中的。
public int MyValue;这是个int型也就是值类型,根据上面第2句(值类型和指针总是放在它们被声明的地方)可以知道它也是放在堆中的,是吧。
所以上面第2张图我也能理解。好,既然是这样的话,我们看第一个例子的代码,他只不过是个方法而已。我认为要执行这个方法之前肯定要先有一个类是吧。
既然这方法执行之前肯定有类包含的话,那不和第2个例子一样么?
就这点我不明白,如果按照文章里代码只给个方法理解那倒没什么问题。但是执行的时候不是这方法外肯定有类的么~那还不是都放在堆上了。
呵呵,也许我钻牛角尖了~
迷惑~~
在学习过程中,有点疑问,请大虾们参考下~
首先下面是文章里的原话:
1. 引用类型总是放在堆中。(够简单的吧?)
2. 值类型和指针总是放在它们被声明的地方。(这条稍微复杂点,需要知道栈是如何工作的,然后才能断定是在哪儿被声明的。) 然后他举例说明
假如我们执行以下的方法:
第一个例子
public int ReturnValue()
{
int x = new int();
x = 3;
int y = new int();
y = x;
y = 4;
return x;
}第二个例子
假如我们首先使用MyInt类
public class MyInt
{
public int MyValue;
}
接着执行以下的方法:
public int ReturnValue2()
{
MyInt x = new MyInt();
x.MyValue = 3;
MyInt y = new MyInt();
y = x;
y.MyValue = 4;
return x.MyValue;
}以上的他讲的是很清楚,我也明白。但是有一个小小的疑问
public class MyInt
{
public int MyValue;
}
这段代码按照开头那2句话和图解,MyInt是个类也就是引用类型,理所当然是放置在堆中的。
public int MyValue;这是个int型也就是值类型,根据上面第2句(值类型和指针总是放在它们被声明的地方)可以知道它也是放在堆中的,是吧。
所以上面第2张图我也能理解。好,既然是这样的话,我们看第一个例子的代码,他只不过是个方法而已。我认为要执行这个方法之前肯定要先有一个类是吧。
既然这方法执行之前肯定有类包含的话,那不和第2个例子一样么?
就这点我不明白,如果按照文章里代码只给个方法理解那倒没什么问题。但是执行的时候不是这方法外肯定有类的么~那还不是都放在堆上了。
呵呵,也许我钻牛角尖了~
迷惑~~
{
public int MyValue;
}
那这个怎么说呢? 类里的变量,使用值类型,也是在栈?堆? 有点晕~
注意,不要把声明和定义具体对象搞混乱了
声明定义同存储无关,不要去套在一起
和存储有关的只是形成对象的时候,也就是new的时候
也就是说new的时候,new的是值类型,这个值类型就放在栈里
如果new的是引用类型,那么放在栈里的就是指针,具体信息在堆里
public int ReturnValue()
{
int x = new int(); //分配了具体对象x
x = 3;
int y = new int();
y = x;
y = 4;
return x;
}public class MyInt
{
public int MyValue; //写法和上面函数注释的x接近,但是这里不分配空间,不要想着存储的事情,这里只是定义声明
}public int ReturnValue2()
{
MyInt x = new MyInt(); //这里开始才建立对象,分配存储,很明显引用类型,当然堆里
x.MyValue = 3;
MyInt y = new MyInt();
y = x;
y.MyValue = 4;
return x.MyValue;
}
再次强调存储分配数据只和对象有关(只有对象占有存储,类声明是抽象概念不占有存储空间,这句话不要钻牛角尖,这是程序和程序员角度理解的,当然站在编译器角度都占有存储空间),和类这个抽象概念无关。到底在堆里还是在栈里,要看分配存储空间的时候看也就是形成对象(new)的时候,和声明定义的时候无关。
MyValue是类的成员,声明对象的时候需要分配内存,这个内存是属于该对象的,所以在堆中。
类的成员方法中的局部变量不是类的成员,在声明对象的时候不会分配内存,只有在调用该方法时才会被分配内存,该内存是跟对象无关的,所以在栈中。
所以首先区分类成员和方法中局部变量的区别。不知道我这样说好不好理解
这句和上面14楼gogogo兄弟的貌似有冲突撒
lz把类定义声明和成员变量定义的内容同定义具体对象搞混了
注意,不要把声明和定义具体对象搞混乱了
声明定义同存储无关,不要去套在一起
和存储有关的只是形成对象的时候,也就是new的时候
也就是说new的时候,new的是值类型,这个值类型就放在栈里
如果new的是引用类型,那么放在栈里的就是指针,具体信息在堆里 是我理解错了? 到底声明类的对象的时候要分配内存,而且已经在堆中?
定义类和声明对象是两个东西
类的定义就是你的原代码,是一个模板,除了它的静态成员外它不会被分配其它内存
对象是类的一个实例,它是根据类这个抽象模板实例化出来的一个具体,C#中,通过new 关键字通知系统声明一个该类型的对象
所以我说的跟gogogo说的不矛盾
{
static void main()
{
A a; // 此处声明了一个类a的引用变量,它其实是一个指针而不是对象,注意,此时它指向Null,
a = new A(); // 此处声明了一个类A的对象,clr会给它分配内存,并将它的句柄传给引用变量a,a此时指向这个新声明的对象
(new A()).a = 10; // 声明了一个对象,但是没有任何引用变量持有它的句柄,这个对象在内存中会一直存活到下一次垃圾收集
A b = a; // 此时b引用变量握有a指向对象的相同句柄
}
}
public class A
{
public int a;
}