class Test
{
interface IAddOne
{
int AddOne();
}
struct FixPoint : IAddOne
{
int _x;
public FixPoint(int x)
{
_x = x;
}
public int AddOne()
{
++_x;
return _x;
}
}
static void Main()
{
ArrayList pointList = new ArrayList(1);
FixPoint f = new FixPoint(0);
pointList.Add(f);
Console.Write(f.AddOne());
Console.Write(f.AddOne());
Console.Write(f.AddOne());
Console.WriteLine();
// Console.WriteLine(pointList[0]); // 输出结果为ConsoleApplication1.Test+FixPoint Console.Write(((IAddOne)pointList[0]).AddOne()); FixPoint p = (FixPoint)pointList[0];
Console.Write(p.AddOne());
Console.Read();
}
}
前面经过3次调用,_x的值变为3,保留在栈中,这道题的结果为啥不是12345,或者12314?
难道后两次输出不会关联到前3次?为啥最后一次输出会关联到第四次输出?(第四次输出1,第5次输出2)
解决方案 »
- 求解答
- 有一只钟表,指针厂4分米,分针长6分米指针呵分针转动一周各行多少分米公式帮算出来啊
- C# 在word指定位置插入图面 求代码。。
- 请问有.net语言的类似Jess的专家系统工具吗?
- 新年到了,给大家做点贡献,分享一下自己的研究成果:C#利用DataGridView实现数据的快速输入
- 求软件reflector for .net~~~~
- 如何修改系统滚动条!(winform控件)3435454
- access数据库,主键为自动编号递增
- 图片的显示方向问题
- 在.NET如何建立与MYSQL的连接
- C#可以直接读取内存么?如果可以的话,仅仅是读取会对系统造成危险么?
- 写了一个程序,但是程序进程不能正常关闭,如何查看原因?
pointList.Add(f);
问题的关键在这句。弄明白这句做什么事,你的疑问就消除了。如果没想清楚,从标题找答案,也可以适当修改程序,便于加深理解。FixPoint p = (FixPoint)pointList[0];
Console.Write(p.AddOne());=》FixPoint p = (FixPoint)pointList[0];
Object obj = pointList[0];
Console.Write(p.AddOne());
Console.Write(((FixPoint)obj).AddOne());
Object obj = pointList[0];
Console.Write(p.AddOne());
Console.Write(((FixPoint)obj).AddOne());
接口保存在堆 是错误的断言。
{}
struct b:a
{}
a a1 = new b
a1保存在啥地方呢?
Console.Write(f.AddOne());
Console.Write(f.AddOne());
Console.Write(f.AddOne()); Console.WriteLine();
Console.WriteLine(pointList[0]); Console.Write(((IAddOne)pointList[0]).AddOne());//值类型,保存在栈上 //FixPoint p = (FixPoint)pointList[0];//引用类型,保存在受管制的堆上
//Console.Write(p.AddOne()); FixPoint p = (FixPoint)pointList[0];
Object obj = pointList[0];
Console.Write(p.AddOne());
Console.Write(p.AddOne());
Console.WriteLine(p.AddOne());
Console.Write(((FixPoint)obj).AddOne()); Console.Read();
123
ConsoleApplication1.Test+FixPoint
1234
2
FixPoint f = new FixPoint(0);
pointList.Add(f);//装箱且发生复制 Pointlist[0] 和 f已经没有关系了
Console.Write(f.AddOne());
Console.Write(f.AddOne());
Console.Write(f.AddOne());
Console.WriteLine();
Console.Write(((IAddOne)pointList[0]).AddOne());//这里通过interface直接对pointlist[0]操作 FixPoint p = (FixPoint)pointList[0];//解装箱且发生复制 p和pointlist[0]没有关系了
Console.Write(p.AddOne());
Console.Read();
------------------------------------------------------
p和pointlist[0]没有关系了 不是的
这里两处发生的都是拆箱操作吧?貌似看你这么解释,好像跟哪些局部变量,结构,接口存在堆和栈完全没关系了
FixPoint p = (FixPoint)pointList[0];
Object obj = pointList[0];
Console.Write(p.AddOne());
复制出来新对象与原有的一点关系都没有了,
在内存中会占用一个新的空间
而引用类型 只是地址引用
struct 是值类型
所以在pointList.Add(f); 时已经做了装箱 被复制
所有的对f 的操作 不会影响到 pointList
如果 把struct 改成 class
输出的内容 就会是12345 因为类是引用类型 只是引用了 对象的地址,
并不是实际的值 ,所有的操作都会影响到原对象。
我理解的!嘿,
interface a{}
你不能 a a1 = new a()
而且他能够被引用类型和值类型,实现所以不能所接口就是引用类型,就是值类型
所谓的装箱
就是从栈中把变量复制到堆中,反装箱就是相反的操作
interface a = pointlist[] ,因为interface 的不确定性,所以不引起反装箱
Farpoint p = pointlist[]则引起了反装箱
之后
pointList[0]._X == ???
改成
((FixPoint)(pointList[0])).AddOne();
((IAddOne)(pointList[0])).AddOne();
之后呢??
运行一下就清楚了
----------------------------------
是我搞错了,装箱操作会产生副本的。hdt大叔是对的,“因为interface 的不确定性,所以不引起反装箱
” 只是这句我不赞同。有时间会把这个事详细说清楚。
Console.Write(((IAddOne)pointList[0]).AddOne());==》修改成 Console.Write(((FixPoint)pointList[0]).AddOne()); 4和5的输出就是11
这个是针对struct类型的
但是当struct改成clas时,结果就是12345 可见当为clss时都是引用同一个对象
个人总结:strut为值类型 封箱和拆箱都是复制对象 而当为引用类型时 则都引用同一个对象。
http://hi.csdn.net/space.html
pointList.Add(f);
这一行代码导致f被从栈中装箱后放到了托管堆上,堆上的对象是复制的_x是0的FixPoint;现在堆上的object类型和栈上的f没有关系了,所以调用f.AddOne()是不会影响堆上对象的_x的下面的代码是将堆上的object类型转换成IAddOne,这时候堆上_x在AddOne调用之前是0,调用后输出是1,IAddOne接口是引用类型,他调用后直接改变堆上的值
Console.Write(((IAddOne)pointList[0]).AddOne());//下面一行代码需要将堆上的object(注意这时候他的_x字段是1)拆箱,然后复制到栈上,复制到栈上时他的_x是1
FixPoint p = (FixPoint)pointList[0];
//再次AddOne自然是在1的基础上加1
Console.Write(p.AddOne());有关装箱和拆箱看下我的博客吧
http://www.cnblogs.com/yukaizhao/archive/2011/10/18/csharp_box_unbox_1.html
pointList.Add(f);
这一行代码导致f被从栈中装箱后放到了托管堆上,堆上的对象是复制的_x是0的FixPoint;现在堆上的object类型和栈上的f没有关系了,所以调用f.AddOne()是不会影响堆上对象的_x的下面的代码是将堆上的object类型转换成IAddOne,这时候堆上_x在AddOne调用之前是0,调用后输出是1,IAddOne接口是引用类型,他调用后直接改变
堆应该是栈上的f的值Console.Write(((IAddOne)pointList[0]).AddOne());//下面一行代码需要将堆上的object(注意这时候他的_x字段是1)拆箱,然后复制到栈上,复制到栈上时他的_x是1
FixPoint p = (FixPoint)pointList[0];
//再次AddOne自然是在1的基础上加1
Console.Write(p.AddOne());有关装箱和拆箱看下我的博客吧
http://www.cnblogs.com/yukaizhao/archive/2011/10/18/csharp_box_unbox_1.html
Visual Studio 2010 Other Versions Visual Studio 2008 Visual Studio 2005 Visual Studio .NET 2003 Variables of reference types, referred to as objects, store references to the actual data. This section introduces the following keywords used to declare reference types: classinterfacedelegateThis section also introduces the following built-in reference types: dynamicobjectstringhttp://msdn.microsoft.com/en-us/library/490f96s2.aspx
using System.IO;
using System.Text;
using System.Linq;
using System.Collections;
using System.Collections.Generic;class Hello {
static void Main() { ArrayList pointList = new ArrayList(1);
FixPoint f = new FixPoint(0); // 此处引起装箱, f 和 pointList[0] 虽数据相同,却已经不是同一个对象了。
// f 指向的是 栈 中的对象,而 pointList[0] 却指向的是 堆中 被装箱的对象。
pointList.Add(f);
Console.Write(f.AddOne());
Console.Write(f.AddOne());
Console.Write(f.AddOne());
Console.WriteLine();
Console.WriteLine(pointList[0]); // 输出结果为FixPoint
Console.WriteLine(((FixPoint)pointList[0])._x); //输出为 0 Console.WriteLine(((IAddOne)pointList[0]).AddOne());//输出为 1 强制转换为 接口 ,不会导致拆箱
Console.WriteLine(((FixPoint)pointList[0]).AddOne());//输出为 2 强制转换为 stuuct ,会导致拆箱 ,修改的是复制到 栈 中的对象 FixPoint p = (FixPoint)pointList[0]; //拆箱发生复制 p和pointlist[0]没有关系了
Console.WriteLine(p.AddOne()); //输出为 2
Console.WriteLine(((FixPoint)pointList[0])._x); //输出为 1 Console.Read();
} public static void wl(String format, params Object[] arg) {
Console.WriteLine(format, arg);
}
} interface IAddOne
{
int AddOne();
}
struct FixPoint : IAddOne
//class FixPoint : IAddOne
{
public int _x;
public FixPoint(int x)
{
_x = x;
}
public int AddOne()
{
++_x;
return _x;
}
}