回复:lerit的关于对象中字段的初始化问题

     谢谢lerit的对于我的博文《内存探寻1之——值类型和引用类型的内存分配机制》中提到的问题。这里先重述问题:

 "你好,你的文章写得很好,清晰了很多以前比较模糊的概念,我想提个问题,上面你总结了自定义对象的过程,那三条是按照顺序的吗?
另外,下面这个类,是先实例化字段,还是先构造器,我从第三条中看出是“初始化构造器,对对象字段初始化”,可是好像是构造函数后执行了,请指教

public class c
{
public int a = 9;
public c()
{
a = 0;
}
}"

 

其实我对于字段的初始化以前没有在意,在这里谢谢你的评论,使我关注到了它。我的解释是:

 

我的分析:

首先:我理解你的问题主要是:类中的字段(ex,上例中的 a)的初始化问题! (呵呵,希望没有错~);

其次:我对于对象的内存分配顺序是(由博文《内存探寻1之——值类型和引用类型的内存分配机制》):

 

1.构造实例化对象中TypeHandler所指向的对象(可认为是Method Table),包括实现接口、静态字段、方法等,并提交至Loader Heap上;

2. 初始化实例的2个附加成员(TypeHandler和SyncBlockIndex),并且将TypeHandler指针指向Method Table;

3.初始化构造器,对对象字段初始化;

 

我想用一例子看一下效果:

 1 //Description: 通过建立类TestClass,演示对象的内存分配机制
 2 
 3 //CopyRight: http://www.cnblogs.com/yangmingming
 4 
 5 //Notes: 为简便,将类的建立,和实例化类放于一起
 6 
 7 namespace ConsoleApplication1
 8 {
 9    public  class TestClass
10     {
11        public int c ;
12 
13        public TestClass(int cc)
14        {
15            c = cc;
16        }
17     }
18 }
19 
20 class Program
21     {
22         static void Main(string[] args)
23         {
24             TestClass tc = new TestClass(5);
25             Console.WriteLine(tc.c);
26         }
27     }
28 //输出为:5 

  为说明方便,我们在15行设定断点,经调试,其界面为:

 

可见,如你所言,对象中字段在调用构造函数前,已经有值了!然而在这里我想我们的理解会有误差,具体分析如下:

一: 我上面所讲的"初始化构造器,对对象字段初始化",可以肯定的说,你理解的与我不同(呵呵,必须的~)。我的理解是——调用构造函数,而其主要作用是对其中字段初始化!(你的理解是先后顺序执行?!);

二:我认为可以认为类中字段的直接赋值(如你例中:public int a = 9;) 为在内存直接分配完毕后,给字段相应位置赋值,这或许可以被称为字段初始化(虽然我对这种方式不甚熟悉)。即:对字段的赋值是在我的上述对象内存分配过程3过程之前执行的!

三:从我的上例中看到,当未对字段赋初值时(实质上,系统出于C#的类型安全性要求会对字段类型分别赋初值0或null), 在调用构造函数前字段已经采取了初始赋值:0;

 

附:之所以会对我的说明产生误解(或者,我的说明不清晰)主要因为

1;在C++中,构造函数的作用即:为字段赋初值;

2:关于初始化,在C++中是不允许直接使用: public int a = 9;的,这样会报错。它采用了一种比较特殊的为字段初始化的方式(提供默认值-声明与定义分离,这里不阐述)。而C#中的字段初始化应在内存分配完成后直接完成的;

3:因为我虽然学习了C#,可能由于还没有在工作中更多实践,所以C++思想还很"丰富"的缘故(呵呵,尽快转变~);

 

最后,还是感谢lerit的问题,让我有了更多思考,希望以后继续交流!

 

 

 

 

 

 

posted @ 2010-02-09 23:23  Youngman  阅读(479)  评论(1编辑  收藏  举报