首先,对我的描述中的一些关键名词做出限定,以免因词汇含义不一致而导致不必要的误解。用作限定名词的示例代码:
class A
{
private int _someData;
public int SomeData
{
get{return _someData;}
set{_someData = value;}
} public void DoNothing()
{;}
}class B
{
public void DoWork()
{
A a = new A();
A a1 = a;
object b = (object)a; //此处可以采取隐式转换,但为了明确、醒目起见,使用了强制转换
a.DoNothing();
}
}对象:类的实例,在上例中,即指new运算符执行时在托管堆上创建的A类的一个实例;
引用变量:偶尔也简称为引用,在上例中即指变量a、a1、b;
托管堆:有时简称堆,但与非托管堆是有区别的,当说到非托管堆时,不会简称为堆 //个人习惯
栈:即堆栈,二者含义一致,堆栈一词可以理解为偏义词-----------------------------------激情的分割线----------------------------------------------------------------下面讲讲我的观点,抛砖引玉,望大家不吝赐教!1、过程分析A a = new A(); //执行时,在托管堆上创建一个A类的实例,在栈上创建一个引用变量a,该引用变量指向(或称引用)上述实例A a1 = a; //执行时,没有创建新的A类的实例,在栈上创建了新的引用变量a1,a1与a指向同一个实例,但是a1与a本身存储在栈上的不同位置,并非同一个东西object b = (object)a; //执行时,没有创建新的A类的实例或object实例,在栈上创建了新的引用变量b,b与a也指向同一个实例,至此,a,a1,b指向均同一个实例2、关于引用变量1)引用变量指向一个对象(类的实例),但是引用变量本身并非对象本身,不可混淆,二者存储位置不同。对象存储在堆上,而引用变量存储在栈上。2)引用变量一旦定义,永远只能指向定义时所确定的类型或其子类型。如上示例中的a,被定义为对A类型的引用,则尝试让a指向其他类型(如object)时编译出错。3)使用某类型的引用变量时,只能访问实例中在该类型层次上所暴露出来的成员(成员包括字段、属性和方法)先说这么多吧,欢迎大家斧正,感谢大家参与!
class A
{
private int _someData;
public int SomeData
{
get{return _someData;}
set{_someData = value;}
} public void DoNothing()
{;}
}class B
{
public void DoWork()
{
A a = new A();
A a1 = a;
object b = (object)a; //此处可以采取隐式转换,但为了明确、醒目起见,使用了强制转换
a.DoNothing();
}
}对象:类的实例,在上例中,即指new运算符执行时在托管堆上创建的A类的一个实例;
引用变量:偶尔也简称为引用,在上例中即指变量a、a1、b;
托管堆:有时简称堆,但与非托管堆是有区别的,当说到非托管堆时,不会简称为堆 //个人习惯
栈:即堆栈,二者含义一致,堆栈一词可以理解为偏义词-----------------------------------激情的分割线----------------------------------------------------------------下面讲讲我的观点,抛砖引玉,望大家不吝赐教!1、过程分析A a = new A(); //执行时,在托管堆上创建一个A类的实例,在栈上创建一个引用变量a,该引用变量指向(或称引用)上述实例A a1 = a; //执行时,没有创建新的A类的实例,在栈上创建了新的引用变量a1,a1与a指向同一个实例,但是a1与a本身存储在栈上的不同位置,并非同一个东西object b = (object)a; //执行时,没有创建新的A类的实例或object实例,在栈上创建了新的引用变量b,b与a也指向同一个实例,至此,a,a1,b指向均同一个实例2、关于引用变量1)引用变量指向一个对象(类的实例),但是引用变量本身并非对象本身,不可混淆,二者存储位置不同。对象存储在堆上,而引用变量存储在栈上。2)引用变量一旦定义,永远只能指向定义时所确定的类型或其子类型。如上示例中的a,被定义为对A类型的引用,则尝试让a指向其他类型(如object)时编译出错。3)使用某类型的引用变量时,只能访问实例中在该类型层次上所暴露出来的成员(成员包括字段、属性和方法)先说这么多吧,欢迎大家斧正,感谢大家参与!
四星用户的观点是:
基本上,那个大牛们是看c入门书走火入门了,所以生搬硬套地说.net的对象是地址。 在.net中,对象就是对象,你不要玩什么“地址”概念,也就不会有此多此一举的困惑。对象有HashCode,但是归根结底还是对象的类型转换,而不是什么地址在两个对象之间的赋值。
MyClass x = new MyClass();
MyClass y=x;
IMyInterface a=(IMInterface)x;
IMyInterface2 b=(IMInterface2)x;
Object c=x; 这里,x、y、a、b、c,都是同一个对象,而不是什么地址相同的不同对象。调用a定义的某个方法,其实就是调用x所代表的对象的那个方法,也同时就是调用b多代表的那个对象的那个方法。你甚至可以写: IMyInterface2 d=(IMInterface2)a; 对毫不相干的类型的对象进行强制类型转换。
如果你打印 x.GetHashCode();
y.GetHashCode();
a.GetHashCode();
b.GetHashCode();
c.GetHashCode();
d.GetHashCode(); 你会发现是完全一样的。有人说,如果类型B继承自A,那么B的实例中就有一个私有对象指向内部的一个A类型的对象,这是错误的结论,则往往给你带到错误的概念上去推理。在多年以前某些c++的书籍作者是这样写的,甚至某些c++实现也真的是那样实现的,但是这是一个对继承的误解。至少在.net中,并不是这样的。
那个大牛们是看c入门书走火入门了,所以生搬硬套地说.net的对象是地址 --> 那个大牛们是看c++入门书走火入魔了,所以生搬硬套地说.net的对象是地址
----------------------------------------------------------------------------------------------------
四角用户的观点是 :
在这里可以将接口看成是一个纯抽象类,其实实现它的类跟它也是继承关系,它们之间也可以看成是"is a"关系。
只是接口更强调的是对外部提供了那些操作,继承它的类一定要实现它的方法,所以你知道如果一个类继承了一个接口的话,那么
这个类一定提供了接口中声明的方法的实现。 你可以将接口看成是提供了一种标准,比如客户提出一个标准,只要我给出满足这个标准的插件,就一定能在客户的程序中正常使用。
要了解基本原理就要了解本质,归根结底程序还是对内存块的操作,了解c的对象和指针无疑对.net中的
对象的理解有很大帮助。 MyClass x = new MyClass();
MyClass y=x;
IMyInterface a=(IMInterface)x;
IMyInterface2 b=(IMInterface2)x;
Object c=x; 这里的x,y,a,b,c其实并不是对象,而是类型分别为MyClass,IMyInterface,Object的引用变量,这些变量的值其实是整型,对应内存中的一个地址,而这个地址就是存储对象的内存块的起始地址。
而真正的对象是通过new操作符在内存中创建的那段内存中的数据结构。 做个很简单的实验: C# code
using System; public class Program
{
static void Main()
{
A obj1 = new A();
A obj2 = new A();
obj1.i = 10;
Method1(obj1);
Console.WriteLine(obj1.i.ToString());
obj2.i = 10;
Method2(ref obj2);
Console.WriteLine(obj2.i.ToString());
}
static void Method1(A obj)
{
Console.WriteLine((++obj.i).ToString());
}
static void Method2(ref A obj)
{
Console.WriteLine((++obj.i).ToString()) ;
}
} public class A
{
public int i;
}
输出:----------------
11
11
11
11
C# code
using System; public class Program
{
static void Main()
{
A obj1 = new A();
A obj2 = new A();
obj1.i = 10;
Method1(obj1);
Console.WriteLine(obj1.i.ToString());
obj2.i = 10;
Method2(ref obj2);
Console.WriteLine(obj2.i.ToString());
}
static void Method1(A obj)
{
obj = new A();
obj.i = 15;
Console.WriteLine(obj.i.ToString());
}
static void Method2(ref A obj)
{
obj = new A();
obj.i = 15;
Console.WriteLine(obj.i.ToString()) ;
}
} public class A
{
public int i;
}
输出:
15
10
15
15 可以看出,例1中的两个方法都改变了实参,而例2中obj1却没有被改变。为什么
如果不知道传参的实质的话这里是很难解释的。 引用变量作为参数时传递的是对象的引用,其实它任然是值传递,只不过这里的值,是对象的引用,即地址,型参中引用变量
obj拷贝了它的实参obj1的值,即obj1指向的对象地址,所以,直接通过型参obj去改变对象的状态也会影响到Main中的obj1,
此时相当于
形参-------->堆中的数据结构 <------------实参
而如果加上ref强制进行引用传递,此时实际上是将值类型A的引用变量的引用传给了形参,此时的形参相当于引用的引用,即指针的指针,所以此时声明一个新对象并将其引用赋给形参会影响到实参,而同样的操作用值传递就不会影响到实参
此时相当于
形参------->实参--------->堆中的数据结构
C#的核心仍然是C++
CLR也只不过是运行在宿主进程上的一个软件层罢了,归根结底程序运行的机制是相同的,只不过C#是类型安全的而且不允许
使用指针罢了,但是通过标记标记unsafe仍然可以使用指针 C++是源头啊,源头啊,源头啊,源头啊(回想1万遍啊1万遍)
就如同汇编是老祖宗啊老祖宗
就如同其实都是机器码啊机器码
争论起源:
http://topic.csdn.net/u/20090227/15/1b3226fb-b13c-4755-9ce0-ac70a20a0b67.html
Apress.Expert Visual C++CLI .NET for Visual C++ Programmers_Updated.pdf
16 页 对
Tracking Handles
的讲述跟楼主的部分一致.可以将引用类型的变量 '看作' 一个受限制的指针,
不可取变量本身的值来用, 那个值就是对象在托管堆上的地址, 为啥不可, 因为 GC 会搞它.
也不可对它执行指针运算.
但是大部分行为方式都像指针.
不过我还是认为将声明的引用变量解释为对象本身还是不严谨的,很多情况下会误导人另外,现在开发项目确实应该从需求、业务实现、人力成本、开发周期上着手,软件工业化肯定是软件行业巨大的进步,这也是java和.net诞生的原因不过,作为在这个行业中的个体来说,了解更多实现的本质对个人的成长还是很有必要的,了解底层并不一定就要去开发编译器或者去写个操作系统
但是这对开发高质量和高效率的产品还是很有帮助的,至少遇到一个问题时你能根据实际需要做出更适合的选择
其实没什么好争辨的仅仅是楼主与原帖那位楼主的理解错误加之 四星与四角争辨 这个相当有诱惑的“狗仔队最爱”所导致的而已
我本人也是持与你此段描述相同的观点。我也从未说过引用变量就是指针,若拿它与指针比较时,我一般会说它近似的可以理解为类型安全的指针。类型安全的保障,即本贴所述:2)引用变量一旦定义,永远只能指向定义时所确定的类型或其子类型。如上示例中的a,被定义为对A类型的引用,则尝试让a指向其他类型(如object)时编译出错。
核心争辩就在这里,初学者是否需要明确理解引用变量和它所指向(或称引用)的实例对象的区别。试想,如果不加区分,在初学者眼里,a,a1就会被理解为和它所指向的对象是同一个东西。那么,在遭遇ref关键字时,这种理解就会带来很大的问题。你将如何为初学者解释使用ref方法时发生的事情呢?
我更加倾向 四角的观点:
引用变量作为参数时传递的是对象的引用,其实它仍然是值传递,只不过这里的值,是对象的引用,即地址,型参中引用变量 我认为仍然从较为底层的观点来分辨,才能把握ref的实质,让初学者也能够清晰理解,不至于在使用中犯错。盼释疑。
http://services.social.microsoft.com/feeds/FeedItem?feedId=dae624ea-2aba-4282-a4d7-83a3579c9d07&itemId=c7917e6b-3cf2-452a-b40b-c5ca321db3c1&title=References+are+not+addresses&uri=http%3a%2f%2fblogs.msdn.com%2fericlippert%2farchive%2f2009%2f02%2f17%2freferences-are-not-addresses.aspx&k=fypu7w6lbdNI%2bYOUmLupkB7p1eeKu6HGDGm1uvyKL6I%3d