关于值类型和引用类型

TheNextGates 2014-07-25 07:44:34
总是搞不清楚值类型和引用类型的本质区别,哪位大神能给一个比较通俗易懂的解释,什么指针什么的听完就忘啊,最好有代码示例,还有那个 Public void ss(params String[] array)
{
//代码段

};
中的params是什么意思,加params是什么目的,它也能达到引用类型的效果吗?
...全文
132 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
TheNextGates 2014-07-30
  • 打赏
  • 举报
回复
引用 1 楼 Cnwanglin 的回复:
值类型:直接存储数据的值,保存在内存中的stack(堆栈)中   引用类型:存储对值的引用,实际上存储的就是一个内存的地址.引用类型的保存分成两块,实际值保存在托管堆(heap)中.实际值的内存地址保存在stack中   当使用引用类型时先找到stack中的地址,再找到heap中的实际值.   也就是说保存引用类型时要用到stack和heap,但使用引用类型时我们实际上只用到stack中的值,然后通过这个值间接的访问heap中的值   C#预定义的简单类型,像int,float,bool,char都是值类型,另外enum(枚举),struct(结构)也是值类型   string,数组,自定义的class就都是引用类型了.其中的string是比较特殊的引用类型.C#给它增加个字符恒定的特性.   C#函数的参数如果不加ref,out这样的修饰符显式申明参数是通过引用传递外,默认都是值传递.   这里要注意的一个问题是,参数的类型是值类型还是引用类型和传参数时用值传递还是引用传递是两个不同的概念.   假如有void FunTest(int [] array) 和void FunTest(int a) 这两个函数.参数array是引用类型,a是值类型.但是他们传递时都是按值传递.   我们来举个例子说明下   按值传递参数:   class Program   {   public static void ChangeInt(int num)   {   num = 123;   }   public static void ChangeArray(int[] array)   {   array[0] = 10;   array = new int[] { 6, 7, 8, 9 };   }   static void Main(string[] args)   {   int anum = 1;   int[] aarray = { 1, 2, 3 };   ChangeInt(anum);   ChangeArray(aarray);   Console.WriteLine("value of num: " + anum);   Console.Write("value of aarray: ");   foreach (int i in aarray)   Console.Write(i + " ");   }   }   结果是:value of anum : 1   value of aarray :10 2 3   可能看到结果会有点奇怪.我们一般认为值传递就是把值拷贝一份,然后不管在函数中对传入的参数做啥改变,参数之前的值不会受啥影响,所以anum没有变成123,仍然是1   但是aarray[0]为啥却变成10了呢?   前面我们有说到引用类型在内存中是保存为两个部分,一个是stack中的内存地址,另一个是heap中的实际值.用时我们只直接用stack中的值,我们假如stack中的值为0xabcdefgh ,就说是aaraay指向它吧. 那么我们按值传递时就是把这个stack的值拷贝成另一份就假如是array指向它吧.跟拷贝anum的值1一样.   但是我们操作内存地址这样的值时不会像整数一样直接操作它,而只会通过它去找heap中的实际值.   于是我们array[0] = 10.改变了实际上还是heap中数组的值了. 但array = new int [] {6,7,8,9}没有对之前传的aarray产生影响.这个操作的意义是在heap中重新开辟一块内存,保存着值6,7,8,9. 这这块内存的地址赋给array,于是它之前的值0xabcdefgh被改写了.但aarray指的值stack值仍没变,仍是0xabcdefgh   按引用传递参数   可以用out或ref显式指定.它们大部分时候可以通用,只是有一点细小区别.   先用ref 来举例吧,还用上面的例子,只是加个了关键字ref   class Program   {   public static void ChangeInt(ref int num)   {   num = 123;   }   public static void ChangeArray(ref int[] array)   {   array[0] = 10;   array = new int[] { 6, 7, 8, 9 };   }   static void Main(string[] args)   {   int anum = 1;   int[] aarray = { 1, 2, 3 };   ChangeInt(ref anum);   ChangeArray(ref aarray);   Console.WriteLine("value of num: " + anum);   Console.Write("value of aarray: ");   foreach (int i in aarray)   Console.Write(i + " ");   }   }   结果是:value of anum : 123   value of aarray :6 7 8 9   跟按值传递的结果完全不同吧   num = 123我们是容易理解.我们再来说下aarray的值为啥变了吧   按引用传递时aarray指向的stack中的值不会复制一份,而是直接传过去.这样array[0]= 10这样赋值时也同样改变了heap中 1 2 3 的值,变为10 2 3,如果   没有array = new int [] {6,7,8,9} 这个语句,则它的结果跟上面按值传递是完全一样的.但有个这句话后就不一样,我们知道上面说了它的含义,在heap中开辟一块新内存   值是6 7 8 9,而aarray指向的stack的值被改写了,改为指向保存6 7 8 9的内存地址了.那含有10 2 3的那一块内存其实还继续存在,只是没有谁引用到它了.到时垃圾回收器会把它回收的.   补充:   说下out 和ref的细小区别   ref 传进来的参数必须要先赋值.   像上面 的例子中如果这样写   int num;   ChangeInt(ref int num);   就会出错,必须先给num给个值1.   而且out传进来的参数可以不先赋值.   out num;   ChangeInt(out int num);是对的   另外还有个区别就是如果用out的时候ChangeInt函数中必须有某个地方给num赋值了,而用ref不一定需要在函数中给num赋值   其实这样做的目的很好理解.C#为了确保在任何情况下num必须有个值,不能为空.   因为用ref,在调用函数前必须保证参数有值,所以在函数中就不必要求它一定再赋值   而用out由于在调用函数前不用保证参数必须有值,所以在函数中必须保证给它个值   ChangeInt(ref int num)和ChangeInt(out int num)虽然不一样,但是不同共存,不能当作两个不同的函数   而ChangeInt(int num)和上面 的两个函数是完全不一样的,可以放到一起共存   这样的话调用的时候ref ,out这样的关键字不能省的.必须匹配
你好,关于引用与值传递部分给数组赋值的讲解,我还是没太听懂,比如:array[0]=10,array=new int[]{6,7,8,9}操作之后为什么显示数组时依然是10,2,3,那这个array=new int[]{6,7,8,9}中的6不是放在array[0]里了吗?感谢您的细心解说。
欢乐的小猪 2014-07-26
  • 打赏
  • 举报
回复
值类型放在栈中,引用类型存放在堆中。
devmiao 2014-07-25
  • 打赏
  • 举报
回复
.net中一切都是对象,按理说,只要有引用类型就可以了。 但是.net为性能做了妥协,引入了值类型。引用类型是对象,值类型的本质是“轻量的对象”。
bwangel 2014-07-25
  • 打赏
  • 举报
回复
值类型的赋值是整体拷贝。引用类型的赋值是传地址(String除外)
smthgdin_020 2014-07-25
  • 打赏
  • 举报
回复
引用 楼主 calegequ 的回复:
总是搞不清楚值类型和引用类型的本质区别,哪位大神能给一个比较通俗易懂的解释,什么指针什么的听完就忘啊,最好有代码示例,还有那个 Public void ss(params String[] array) { //代码段 }; 中的params是什么意思,加params是什么目的,它也能达到引用类型的效果吗?
params关键字表示可变参数的意思,就是说你这个方法的参数是可以变化的。 ss("a","b"),ss("a","b","c"),ss("a","b","c","d")都可以。 值类型,引用类型的本质不理解的话也不急,慢慢来。
Cnwanglin 2014-07-25
  • 打赏
  • 举报
回复
值类型:直接存储数据的值,保存在内存中的stack(堆栈)中   引用类型:存储对值的引用,实际上存储的就是一个内存的地址.引用类型的保存分成两块,实际值保存在托管堆(heap)中.实际值的内存地址保存在stack中   当使用引用类型时先找到stack中的地址,再找到heap中的实际值.   也就是说保存引用类型时要用到stack和heap,但使用引用类型时我们实际上只用到stack中的值,然后通过这个值间接的访问heap中的值   C#预定义的简单类型,像int,float,bool,char都是值类型,另外enum(枚举),struct(结构)也是值类型   string,数组,自定义的class就都是引用类型了.其中的string是比较特殊的引用类型.C#给它增加个字符恒定的特性.   C#函数的参数如果不加ref,out这样的修饰符显式申明参数是通过引用传递外,默认都是值传递.   这里要注意的一个问题是,参数的类型是值类型还是引用类型和传参数时用值传递还是引用传递是两个不同的概念.   假如有void FunTest(int [] array) 和void FunTest(int a) 这两个函数.参数array是引用类型,a是值类型.但是他们传递时都是按值传递.   我们来举个例子说明下   按值传递参数:   class Program   {   public static void ChangeInt(int num)   {   num = 123;   }   public static void ChangeArray(int[] array)   {   array[0] = 10;   array = new int[] { 6, 7, 8, 9 };   }   static void Main(string[] args)   {   int anum = 1;   int[] aarray = { 1, 2, 3 };   ChangeInt(anum);   ChangeArray(aarray);   Console.WriteLine("value of num: " + anum);   Console.Write("value of aarray: ");   foreach (int i in aarray)   Console.Write(i + " ");   }   }   结果是:value of anum : 1   value of aarray :10 2 3   可能看到结果会有点奇怪.我们一般认为值传递就是把值拷贝一份,然后不管在函数中对传入的参数做啥改变,参数之前的值不会受啥影响,所以anum没有变成123,仍然是1   但是aarray[0]为啥却变成10了呢?   前面我们有说到引用类型在内存中是保存为两个部分,一个是stack中的内存地址,另一个是heap中的实际值.用时我们只直接用stack中的值,我们假如stack中的值为0xabcdefgh ,就说是aaraay指向它吧. 那么我们按值传递时就是把这个stack的值拷贝成另一份就假如是array指向它吧.跟拷贝anum的值1一样.   但是我们操作内存地址这样的值时不会像整数一样直接操作它,而只会通过它去找heap中的实际值.   于是我们array[0] = 10.改变了实际上还是heap中数组的值了. 但array = new int [] {6,7,8,9}没有对之前传的aarray产生影响.这个操作的意义是在heap中重新开辟一块内存,保存着值6,7,8,9. 这这块内存的地址赋给array,于是它之前的值0xabcdefgh被改写了.但aarray指的值stack值仍没变,仍是0xabcdefgh   按引用传递参数   可以用out或ref显式指定.它们大部分时候可以通用,只是有一点细小区别.   先用ref 来举例吧,还用上面的例子,只是加个了关键字ref   class Program   {   public static void ChangeInt(ref int num)   {   num = 123;   }   public static void ChangeArray(ref int[] array)   {   array[0] = 10;   array = new int[] { 6, 7, 8, 9 };   }   static void Main(string[] args)   {   int anum = 1;   int[] aarray = { 1, 2, 3 };   ChangeInt(ref anum);   ChangeArray(ref aarray);   Console.WriteLine("value of num: " + anum);   Console.Write("value of aarray: ");   foreach (int i in aarray)   Console.Write(i + " ");   }   }   结果是:value of anum : 123   value of aarray :6 7 8 9   跟按值传递的结果完全不同吧   num = 123我们是容易理解.我们再来说下aarray的值为啥变了吧   按引用传递时aarray指向的stack中的值不会复制一份,而是直接传过去.这样array[0]= 10这样赋值时也同样改变了heap中 1 2 3 的值,变为10 2 3,如果   没有array = new int [] {6,7,8,9} 这个语句,则它的结果跟上面按值传递是完全一样的.但有个这句话后就不一样,我们知道上面说了它的含义,在heap中开辟一块新内存   值是6 7 8 9,而aarray指向的stack的值被改写了,改为指向保存6 7 8 9的内存地址了.那含有10 2 3的那一块内存其实还继续存在,只是没有谁引用到它了.到时垃圾回收器会把它回收的.   补充:   说下out 和ref的细小区别   ref 传进来的参数必须要先赋值.   像上面 的例子中如果这样写   int num;   ChangeInt(ref int num);   就会出错,必须先给num给个值1.   而且out传进来的参数可以不先赋值.   out num;   ChangeInt(out int num);是对的   另外还有个区别就是如果用out的时候ChangeInt函数中必须有某个地方给num赋值了,而用ref不一定需要在函数中给num赋值   其实这样做的目的很好理解.C#为了确保在任何情况下num必须有个值,不能为空.   因为用ref,在调用函数前必须保证参数有值,所以在函数中就不必要求它一定再赋值   而用out由于在调用函数前不用保证参数必须有值,所以在函数中必须保证给它个值   ChangeInt(ref int num)和ChangeInt(out int num)虽然不一样,但是不同共存,不能当作两个不同的函数   而ChangeInt(int num)和上面 的两个函数是完全不一样的,可以放到一起共存   这样的话调用的时候ref ,out这样的关键字不能省的.必须匹配

110,502

社区成员

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

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

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