people p=new people()
以上面例子为例当我们用new操作符实例化一个类时,它是这样做的:
1.计算该类型及其所有基类的实例字段所需要的字节数,及该对象的额外对象(类型对象指针,同步索引块)的字节数。
2.根据该对象的大小在托管堆上分配同等大小的空间。
3.初始化对象的类型对象指针和同步索引块。
4.调用该类型的实例构造函数,在此实例构造函数中会调用该类的所有基类的实例构造函数,之后在此实例构造函数中将会初始化这个类型定义的实例字段。
5.返回指向新建对象的一个引用(或指针),这里这个引用会保存在变量p中,p是people类型。
下面来解释类型,对象,线程栈,托管堆在运行时的联系及调用静态方法,实例方法,虚方法的区别。
我们先来定义俩类如下:
public class Person
{
public int Getyear() { return 1; }
public virtual string Getname() { return "michael"; }
public static Person Getperson(int i)
{
if (i = 1)
{
return new Person();
}
else
{
return new Man();
}
}
}
public class Man:Person
{
public void Eat() { }
public override string Getname(){ return "Jackson"; }
}
然后我们在aspx中有一个方法如下:
public void M(int i)
{
Person p;
int year;
p = new Man();
p = Person.Getperson(i);
Label1.Text = p.Getname();
Label2.Text = p.Getyear().ToString();
}
protected void Button1_Click(object sender, EventArgs e)
{
int i = int.Parse(TextBox1.Text);
M(i); ****
}
当****处执行M方法的时候,进程已启动,CLR已加载到其中,托管堆已初始化,也已经创建了一个线程(已经分配了1M空间的栈),这时线程已经执行了一些代码,现在马上要调用M方法,那么此时的图如下:
如果是第一次执行该方法,JIT编译器需要将M的IL代码编译成本地CPU代码。此时CLR会注意到M内的所有类型int,Person,Man。然后加载与这些类型相应的程序集,再根据程序集中的元数据提取与这些类型相关的信息,然后根据这些信息在托管堆上创建相应的类型对象(就是我们平常理解的类),由于int等类型的类型对象一般早就建立了,所以这里就不再画了,这时图如下:
可以看出不光是类的静态字段是所有对象共有的,类的方法其实也是所有对象共有的。当我们写这样一句代码时:new Man().Getyear() CLR会在Man类型对象中找Getyear()方法,找不到回到其基类中找。new Man().Getyear() 就相当于 Man m=new Man(); m.Getyear() 与 Person m=new Man(); m.Getyear()不同。
当所有类型对象都建立完毕且M方法被JIT编译完后,就开始执行M方法了。首先,M方法的"序幕"代码会为M方法中的所有局部变量在线程栈上分配内存。此时图如下:
执行到p = new Man();时将构造一个Man对象(关于new操作上面已经讲述了),不过要注意对象里的实例字段不光是它自身定义的实例字段还包括其所有基类的实例字段,也就是说实例字段不是所有对象共有的,此时图如下:
可以看出Man对象也指向与其类型对应的Man类型对象,尽管对象的引用p是Person类型,此时p只能使用person类型中定义的实例字段及实例方法。 所以调用实例方法看变量引用的类型Person p,其只能使用person类型中的实例方法。
执行到p = Person.Getperson(i);时,调用静态方法没什么好说的,直接使用适应相应的类型调用,会找到相应的类型对象里的静态方法。这里我们假设其仍然返回的是Man对象,此时图如下:
这时变量引用p指向了一个新的Man对象,所以之前的那个Man对象很快就会被GC处理掉。
执行到Label1.Text = p.Getname();这句时,调用的是一个虚实例方法,掉用虚实例方法时要看p是一个什么对象,这里是一个Man对象,所以会调用Man类型对象的Getname()而不是Person类型对象的Getname()。
最后,我们看到那些类型对象也有类型对象指针,所以其实类型对象本身也是对象,它们的类型对象指针指向的是Type类型对象(System.Type),而Type类型对象的类型对象指针指向它自己。而对象的GetType()方法返回的就是该对象中指向类型对象的类型对象指针。而Type类型对象在CLR加载到一个进程中时就创建了。如下图: