一道面试题:解析方法中对象存放以及堆栈之间的关系
2011-03-20 01:36
393 查看
朋友面试遇到一道题是这样的:
namespace Demo
{
internal class Program
{
private static void Main()
{
Person p=new Person("alex");
Upate(p);
Console.WriteLine(p.ToString());
Console.Read();
}
static void Upate(Person p)
{
p=new Person("franck");
}
}
internal class Person
{
private string _name;
public Person(string name)
{
this._name=name;
}
public override string ToString()
{
return this._name;
}
}
}
1,输出的结果是?
2,分析其执行过程
答案是输出结果是:alex
为什么会这样呢,这才是问题所在。好多人会认为在、执行Update方法时对象p发生了改变,事实也是这样的,但为什么结果没有变化,要分析清楚原因,还得看IL
entrypoint
// Code size 38 (0x26)
.maxstack 2
.locals init ([0] class Demo.Person p)
IL_0000: nop
IL_0001: ldstr "alex"
IL_0006: newobj instance void Demo.Person::.ctor(string)
IL_000b: stloc.0 //从计算堆栈的顶部弹出当前值并将其存储到索引 0 处的局部变量列表中
IL_000c: ldloc.0 //将索引 0 处的局部变量加载到计算堆栈上
IL_000d: call void Demo.Program::Upate(class Demo.Person)
IL_0012: nop
IL_0013: ldloc.0 //将索引 0 处的局部变量加载到计算堆栈上
IL_0014: callvirt instance string [mscorlib]System.Object::ToString()
IL_0019: call void [mscorlib]System.Console::WriteLine(string)
IL_001e: nop
IL_001f: call int32 [mscorlib]System.Console::Read()
Upate Method
.method private hidebysig static void Upate(class Demo.Person p) cil managed
{
// Code size 14 (0xe)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "franck"
IL_0006: newobj instance void Demo.Person::.ctor(string)
IL_000b: starg.s p //将位于计算堆栈顶部的值存储在参数槽中的指定索引处
IL_000d: ret //从当前方法返回,并将返回值(如果存在)从调用方的计算堆栈推送到被调用方的计算堆栈上。
} // end of method Program::Upate
这是所有执行的IL吗,根据我做的注释,这一下应清楚了,事实上Update方法执行是在另一个堆栈上,这个堆栈上的执行结果在没有推送到调用方堆栈,在Main()方法的堆栈中,p对象还是原来的对象。
图示:
Main()
Person p=new Person("alex");
Upate 方法同样会产生一个这样的堆栈,方式和上面相同。关键就在这一句上了
IL_000d: ret //从当前方法返回,并将返回值(如果存在)从调用方的计算堆栈推送到被调用方的计算堆栈上。
当Update堆栈上的对象没有推送到Main()产生的堆栈上的时间,图1堆栈中存放的对象p不变,因而输出结果就是那样!
namespace Demo
{
internal class Program
{
private static void Main()
{
Person p=new Person("alex");
Upate(p);
Console.WriteLine(p.ToString());
Console.Read();
}
static void Upate(Person p)
{
p=new Person("franck");
}
}
internal class Person
{
private string _name;
public Person(string name)
{
this._name=name;
}
public override string ToString()
{
return this._name;
}
}
}
1,输出的结果是?
2,分析其执行过程
答案是输出结果是:alex
为什么会这样呢,这才是问题所在。好多人会认为在、执行Update方法时对象p发生了改变,事实也是这样的,但为什么结果没有变化,要分析清楚原因,还得看IL
entrypoint
// Code size 38 (0x26)
.maxstack 2
.locals init ([0] class Demo.Person p)
IL_0000: nop
IL_0001: ldstr "alex"
IL_0006: newobj instance void Demo.Person::.ctor(string)
IL_000b: stloc.0 //从计算堆栈的顶部弹出当前值并将其存储到索引 0 处的局部变量列表中
IL_000c: ldloc.0 //将索引 0 处的局部变量加载到计算堆栈上
IL_000d: call void Demo.Program::Upate(class Demo.Person)
IL_0012: nop
IL_0013: ldloc.0 //将索引 0 处的局部变量加载到计算堆栈上
IL_0014: callvirt instance string [mscorlib]System.Object::ToString()
IL_0019: call void [mscorlib]System.Console::WriteLine(string)
IL_001e: nop
IL_001f: call int32 [mscorlib]System.Console::Read()
Upate Method
.method private hidebysig static void Upate(class Demo.Person p) cil managed
{
// Code size 14 (0xe)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "franck"
IL_0006: newobj instance void Demo.Person::.ctor(string)
IL_000b: starg.s p //将位于计算堆栈顶部的值存储在参数槽中的指定索引处
IL_000d: ret //从当前方法返回,并将返回值(如果存在)从调用方的计算堆栈推送到被调用方的计算堆栈上。
} // end of method Program::Upate
这是所有执行的IL吗,根据我做的注释,这一下应清楚了,事实上Update方法执行是在另一个堆栈上,这个堆栈上的执行结果在没有推送到调用方堆栈,在Main()方法的堆栈中,p对象还是原来的对象。
图示:
Main()
Person p=new Person("alex");
Upate 方法同样会产生一个这样的堆栈,方式和上面相同。关键就在这一句上了
IL_000d: ret //从当前方法返回,并将返回值(如果存在)从调用方的计算堆栈推送到被调用方的计算堆栈上。
当Update堆栈上的对象没有推送到Main()产生的堆栈上的时间,图1堆栈中存放的对象p不变,因而输出结果就是那样!
相关文章推荐
- OutMan——面向对象的三大特性、对象和对象之间的关系以及动态类型检测方法
- mybatis对象之间映射关系以及数据库表建立的时候外键的添加
- mybatis对象之间映射关系以及数据库表建立的时候外键的添加
- vs工程文件解决方法以及项目之间的关系
- valuestack,stackContext,ActionContext.之间的关系以及action的数据在页面中取得的方法
- 微软企业库4.1学习笔记(二)各功能之间的依赖关系以及对象创建
- mybatis对象之间映射关系以及数据库表建立的时候外键的添加
- mybatis对象之间映射关系以及数据库表建立的时候外键的添加
- 微软企业库Enterprise Library学习笔记二各功能之间的依赖关系以及对象创建
- java线程基础巩固---同步代码块以及同步方法之间的区别和关系
- 【iOS开发-72】设置状态栏的两种方式、程序生命周期以及更好地理解几大类(对象)之间的关系
- “每日一道面试题”.Net中所有类的基类是以及包含的方法
- mybatis对象之间映射关系以及数据库表建立的时候外键的添加
- mybatis对象之间映射关系以及数据库表建立的时候外键的添加
- 【iOS开发-72】设置状态栏的两种方式、程序生命周期以及更好地理解几大类(对象)之间的关系
- 微软企业库4.1学习笔记(二)各功能之间的依赖关系以及对象创建
- Dom解析是将xml文件全部载入,组装成一颗dom树,然后通过节点以及节点之间的关系来解析xml文件,下面结合这个xml文件来进行dom解析。
- new,is和as运算符解析及运行时类型,对象,线程堆栈,托管堆之间的联系
- MFC类的组织(类之间的关系)与WinMain函数、theAPP、构造函数、以及全局变量(对象)之间的关系
- 二.OC基础--1,对象的存储细节,2,#pragma mark指令,3,函数和对象方法的区别,4,对象和方法之间的关系 ,5.课堂习题