c#一道面试题

SeaSunk 2009-07-23 02:36:01
int i = 2000;
object o = i;
i = 2001;
int j = (int)o;
Console.WriteLine("i={0},o={1},j={2}",i,o,j);
Console.ReadKey();

结果是i=2001,o=2000,j=2000

有人可以告诉我吗?为什么o为2000;
...全文
168 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
SeaSunk 2009-12-03
  • 打赏
  • 举报
回复
?没结贴?
mbh0210 2009-07-23
  • 打赏
  • 举报
回复
你这个就是值类型和引用类型的关系,上次的文章值得看看
mbh0210 2009-07-23
  • 打赏
  • 举报
回复
C# 中堆栈,堆,值类型,引用类型的理解 (摘抄) 1,什么是GC
GC的全称是garbage collection,中文名称垃圾回收,是.net中对内存管理的一种功能。垃圾回收器跟踪并回收托管内存中分配的对象,定期执行垃圾回收以回收分配给没有有效引用的对象的内存。当使用可用内存不能满足内存请求时,GC会自动进行。在进行垃圾回收时,垃圾回收器回首先搜索内存中的托管对象,然后从托管代码中搜索被引用的对象并标记为有效,接着释放没有被标记为有效的对象并收回内存,最后整理内存将有效对象挪动到一起。这就是GC的四个步骤。
由上可见,GC是很影响性能的,所以一般说来这种事情况还是尽量少发生为好。
为了减少一些性能影响,.net的GC支持对象老化,或者说分代的概念,代是对象在内存中相对存现时期的度量单位,对象的代数或存现时期说明对象所属的代。目前.net的垃圾回收器支持三代。每进行一次GC,没有被回收的对象就自动提升一代。较近创建的对象属于较新的代,比在应用程序生命周期中较早创建的对象的代数低。最近代中的对象位于零代中。每一次GC的时候,都首先回收零代中的对象,只有在较低代数的对象回收完成后仍不能满足需求的情况下才回收较高代数的对象。

2,读文章,看到了一个关于堆和栈(堆栈)的区别的比喻。很形象:
使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。
使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。

3,GC和堆栈、堆
由前述堆栈和堆的概念可以看出,堆栈不存在垃圾收集的问题,只需要直接压栈即可,而堆,则面临着很复杂的垃圾回收的问题。GC完全是对堆进行操作的,而对堆中对象是否有效的判断则是通过遍历堆栈来实现的。这里涉及到一个引用计数的概念,引用计数是对堆中对象被引用次数的统计,当一个对象的引用计数为零了,那么这个对象就可以被回收了。在进行GC的时候,垃圾回收器遍历堆栈,当发现一个堆地址的时候,它就将堆中该地址上的对象的引用计数加1,然后销毁堆中所有引用计数为零的对象,回收内存并整理堆中的碎片。

4,类实例化的步骤
类是最常见也是我们用的最多的一种引用类型,我们知道实例化一个类使用的是一个我们司空见惯的语句:
ClassA ca = new ClassA();
那么这短短的一句话中,计算机又做了些什么事情呢?
实际上,计算机在这个过程中大致做了这么几件事:
首先,在ClassA ca的时候,生成一个空的引用指针,并将它推入堆栈中:
然后,在new ClassA()的时候,生成ClassA的新的实例,并放入堆中:
在赋值号=这一步,将ca的引用指针指向刚刚生成的新实例:
这个时候,才算完成了整条语句的操作。

5,特例:string 类型与堆
大家知道,string类型是一种引用类型。但它又有一些值类型的特征。比如指向同一个字符串的两个string变量,如果其中一个变量值发生了改变,却不会影响到另外一个string变量。这就是因为:
(1)CLR使用了一种叫字符串驻留的技术,对于
string str1="abc";
string str2="abc";
当CLR初始化时,会创建一个内部的散列表,其中的键为字符串,值为指向托管堆中字符串的引用。刚开始,散列表为空,JIT编译器编译方法时,会在散列表中查找每一个文本常量字符串,首先会查找"abc"字符串,并且因为没有找到,编译器会在托管堆中构造一个新的指向"abc"的String对象引用,然后将"abc"字符串和指向该对象的引用添加到散列表中。
  接着,在散列表中查找第二个"abc",这一次由于找到了该字符串,所以编译器不会执行任何操作,代码中再没有其它的文本常量字符串,编译器的任务完成,代码开始执行。执行时,CLR发现第一个语句需要一个"abc"字符串引用,于是,CLR会在内部的散列表中查找"abc",并且会找到,这样指向先前创建的String对象的引用就被保存在变量s1中,执行第二条语句时,CLR会再一次在散列表中查找"abc",并且仍然会找到,指向同一个String对象的引用会被保存在变量s2中,到此s1和s2指向了同一个引用,所以System.Object.Equals(s1,s2)就会返回true了。
(2)当使用重载操作符”=”给string对象赋值时,string的对象是引用类型,它保留在堆上,而不是堆栈上.因此,当把一个字符串赋给另一个字符串时,会得到对内存中同一个字符串的两个引用.例如,修改其中一个字符串,就会创建一个全新的string对象(注意,这个过程发生在”=”中),而另一个字符串没有改变.

6,C#中值类型分配在堆栈中。
值类型:bool,byte,char,decimal,double,enum,float,int,long,sbyte,short,struct,uint,ulong,ushort.
7,C#中引用类型分配在堆中,在堆栈中创建一个指向到堆的引用,返回给声明的变量。
引用类型:class,delegate,interface,object,string

备注:1. 值类型数组虽然分配在堆上,但数组元素依然是值类型,并没有被装箱。
2, 引用对象的值类型成员也随对象一起分配在堆上,同样也还是值类型,没有被装箱
andyxl 2009-07-23
  • 打赏
  • 举报
回复
// 应该就是值类型和引用类型的原因。
SeaSunk 2009-07-23
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 vrhero 的回复:]
原因很简单...

int i = 2000; //i是值类型对象,值为2000...
object o = i; //装箱(Boxing)...引用类型o的值是一个值为2000的int类型对象,这个对象和i没有关系...
i = 2001; //值类型对象i改变不会影响引用类型o的值...因为它们毫无关系...
int j = (int)o; //拆箱(Unboxing)...值类型对象j和没有关系,和i更没有关系...

这是最最基础的.NET知识,不太可能作为面试题...如果这个题都答不上来,离.NET入门还很远呢...
[/Quote]
谢谢你,那证明我离他很远了。哭。。。。
wwq0123 2009-07-23
  • 打赏
  • 举报
回复
object o = i;
这是一个装箱的过程,装箱在托管堆上新分配一块内存,然后将值复制到新分配的内存上。所以不管存放i值的内存上的值怎么变化都不会影响o的值
vrhero 2009-07-23
  • 打赏
  • 举报
回复
原因很简单...

int i = 2000; //i是值类型对象,值为2000...
object o = i; //装箱(Boxing)...引用类型o的值是一个值为2000的int类型对象,这个对象和i没有关系...
i = 2001; //值类型对象i改变不会影响引用类型o的值...因为它们毫无关系...
int j = (int)o; //拆箱(Unboxing)...值类型对象j和没有关系,和i更没有关系...

这是最最基础的.NET知识,不太可能作为面试题...如果这个题都答不上来,离.NET入门还很远呢...
SeaSunk 2009-07-23
  • 打赏
  • 举报
回复
大家,我想知道原因,结果很明显了。
qlzf11140820 2009-07-23
  • 打赏
  • 举报
回复
int i = 2000; //i=2000
object o = i; //0=2000
i = 2001; //i=2001
int j = (int)o; //j=2000,0=2000
Console.WriteLine("i={0},o={1},j={2}",i,o,j);
Console.ReadKey();
qlzf11140820 2009-07-23
  • 打赏
  • 举报
回复
int i = 2000; //i=2000
object o = i; //0=2000
i = 2001; //i=2001
int j = (int)o; j=2000,0=2000
Console.WriteLine("i={0},o={1},j={2}",i,o,j);
Console.ReadKey();
SeaSunk 2009-07-23
  • 打赏
  • 举报
回复
[Quote=引用楼主 seasunk 的回复:]
          int i = 2000;
            object o = i;
            i = 2001;
            int j = (int)o;
            Console.WriteLine("i={0},o={1},j={2}",i,o,j);
            Console.ReadKey();

结果是i=2001,o=2000,j=2000

有人可以告诉我吗?为什么o为2000;
[/Quote]
为什么呢,是值类型的原因??
zhubo_1117 2009-07-23
  • 打赏
  • 举报
回复
那你认为是多少呢?
object o = i;
因为i是2000所以o是2000啊!
后面的i变化是不会影响o的,两个变量在内存存储的位置都不一样!
wzytiger 2009-07-23
  • 打赏
  • 举报
回复
int i = 2000;
object o = i;
把i赋给o,这个时候i是2000
以后i的值变更和o没有关系!

wdgphc 2009-07-23
  • 打赏
  • 举报
回复
int i = 2000;
object o = i;

以后不管i怎么变化,o一直是2000

110,536

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧