值类型,引用类型的初始化,等值判断,传递和转换
2009-05-07 20:51
211 查看
初始化
首先我们来看这段 代码1
发现什么,编译通过,运行时 call 值类型没有问题,call 引用类型却报错。
再看如下 代码2
直接编译就不通过,什么原因呢
原因在于在class的构造器会自动对所有field自动初始化,所以代码1编译可以通过,代码2方法里的私有字段确无法通过编译。
值数据直接对应的是堆栈,一初始化就自动运行值类型默认的构造器,而引用类型堆栈里的是一个空指针,指向的数据为空。
代码1等价于如下 代码3
正因为值类型将自动call constructor, 避免编程的混乱,.net也不允许值类型自定义无参构造器,因此我们编写struct的时候,也无法自定义无参构造器。
另外在类里用户如果已经有了自定义的构造器,那么编译顺序是首先编译类里字段的初始化,然后再调用自定义构造器。
等值判断和参数传递
还是看代码4
运行结果数值类型和截然不同,怎么造成的呢
所谓等值判断 所判断的就是堆栈里的内容。值类型堆栈里存放就是实际内容,所以值类型的等值判断就是判断数据相同,对于.net来说,就是通过反射,对比2个值类型的内部所有数据是否相同,全部相同则2个值类型相同
而对于引用类型,堆栈里存放的只是地址,只有地址完全相同,2个引用类型才相同,而不管实际对应的数据是什么。
所以开始的2个有相同的数值的值数据做对比返回true,而2个有相同数据的引用类型则返回false。
当2个数据传递的时候,就是1方把堆栈里的数据复制给另一方。对于值类型来说,堆栈里的就是数据,赋值消耗较大,而对于引用类型来说,堆栈里存放的只是1个地址,指向真实数据的地址。
所以当存在2个相等的引用类型,由于存在相同的地址。另一方改变数据,都将影响另一方。
而2个相等的值类型,由于堆栈存的就是数据,1方改变,对另一方没有任何影响。
因此第3个判断为2个值类型,1方改变不影响另一方,返回false,第4个判断2个引用类型,双方一起变化,返回true。
注意:string有点不一样,是引用类型,但是确是数值恒定的引用类型,CLR特别开辟了一个驻留表来保存所有的string数值,所以传递的时候传递的是指针,但数据改变不是影响原来的数据,而是新开一个空间给新数据.
转换
转换可以分2大类
第1类为运算符转换,转换的时候调用类里的转换运算符,又包含implicit operator(隐性转换) explicit operator(显性转换),如:int i=1;long l=1;l=i;i=(int)l;
这里l=i就是隐性转换,i=(int)l为显性转换。
第2类为由于继承关系而产生的转换,子类向父类(或接口)的转换(传递)
如:Employee e=new Employee(); IEmployee ie=e;
这里传递的是指针。虽然语法跟上面运算法转换一样,但实际工作并不一样。
注意:当转换失败的时候运行将会报错。
另外还有专门给类转换用的as转换符,语法如:IEmployee ie=e as IEmployee;
as转换符不支持operator的转换,只传递指针地址。
另外:当as转换失败的时候,并不会报错,而是传递一个空指针,得到1个null数据。
值类型与引用类型之间的转换
上节提到的转换时值类型与值类型,引用类型和引用类型之间的转换,如果是值类型与引用类型之间的转换呢
如object与int之间的转换。
1:值类型转为引用类型,首先将堆栈中值的数据复制到堆里,然后将指针传给引用类型,此步骤称为box(装箱)
2:引用类型转为值类型。根据引用指针获得数据内容,然后把堆中的数据拷贝到堆栈,此步骤称为unbox(拆箱)
显然从这里看的出box与unbox消耗大量资源,及其影响效率,所以对于未知类型的数据应该尽量用泛型,避免使用类似ArrayList等类。
参考
《applied microsoft .net framework Programming》
《Professional c#》
首先我们来看这段 代码1
using System; public class Program { static int i; static object o; public static void Main() { Console.WriteLine(i.ToString());//call val Console.WriteLine(o.ToString());//call ref } }
发现什么,编译通过,运行时 call 值类型没有问题,call 引用类型却报错。
再看如下 代码2
using System; public class Program { public static void Main() { int i; object o; Console.WriteLine(i.ToString());//call val Console.WriteLine(o.ToString());//call ref } }
直接编译就不通过,什么原因呢
原因在于在class的构造器会自动对所有field自动初始化,所以代码1编译可以通过,代码2方法里的私有字段确无法通过编译。
值数据直接对应的是堆栈,一初始化就自动运行值类型默认的构造器,而引用类型堆栈里的是一个空指针,指向的数据为空。
代码1等价于如下 代码3
using System; public class Program { static int i; static object o; public Program() { i=new int();//val type will call default constructor o=null; // ref type assign null } public static void Main() { Console.WriteLine(i.ToString());//call val Console.WriteLine(o.ToString());//call ref } }
正因为值类型将自动call constructor, 避免编程的混乱,.net也不允许值类型自定义无参构造器,因此我们编写struct的时候,也无法自定义无参构造器。
另外在类里用户如果已经有了自定义的构造器,那么编译顺序是首先编译类里字段的初始化,然后再调用自定义构造器。
等值判断和参数传递
还是看代码4
using System; using System.Collections; public class Program { public static void Main() { int i=1; int j=1; RefType r=new RefType();r.id=1; RefType s=new RefType();s.id=1; Console.WriteLine(i==j); //return true Console.WriteLine(r==s); //return false j=i;i=2; s=r;r.id=2; Console.WriteLine(i==j); //return false Console.WriteLine(r==s); //return true } } public class RefType { public int id; }
运行结果数值类型和截然不同,怎么造成的呢
所谓等值判断 所判断的就是堆栈里的内容。值类型堆栈里存放就是实际内容,所以值类型的等值判断就是判断数据相同,对于.net来说,就是通过反射,对比2个值类型的内部所有数据是否相同,全部相同则2个值类型相同
而对于引用类型,堆栈里存放的只是地址,只有地址完全相同,2个引用类型才相同,而不管实际对应的数据是什么。
所以开始的2个有相同的数值的值数据做对比返回true,而2个有相同数据的引用类型则返回false。
当2个数据传递的时候,就是1方把堆栈里的数据复制给另一方。对于值类型来说,堆栈里的就是数据,赋值消耗较大,而对于引用类型来说,堆栈里存放的只是1个地址,指向真实数据的地址。
所以当存在2个相等的引用类型,由于存在相同的地址。另一方改变数据,都将影响另一方。
而2个相等的值类型,由于堆栈存的就是数据,1方改变,对另一方没有任何影响。
因此第3个判断为2个值类型,1方改变不影响另一方,返回false,第4个判断2个引用类型,双方一起变化,返回true。
注意:string有点不一样,是引用类型,但是确是数值恒定的引用类型,CLR特别开辟了一个驻留表来保存所有的string数值,所以传递的时候传递的是指针,但数据改变不是影响原来的数据,而是新开一个空间给新数据.
转换
转换可以分2大类
第1类为运算符转换,转换的时候调用类里的转换运算符,又包含implicit operator(隐性转换) explicit operator(显性转换),如:int i=1;long l=1;l=i;i=(int)l;
这里l=i就是隐性转换,i=(int)l为显性转换。
第2类为由于继承关系而产生的转换,子类向父类(或接口)的转换(传递)
如:Employee e=new Employee(); IEmployee ie=e;
这里传递的是指针。虽然语法跟上面运算法转换一样,但实际工作并不一样。
注意:当转换失败的时候运行将会报错。
另外还有专门给类转换用的as转换符,语法如:IEmployee ie=e as IEmployee;
as转换符不支持operator的转换,只传递指针地址。
另外:当as转换失败的时候,并不会报错,而是传递一个空指针,得到1个null数据。
值类型与引用类型之间的转换
上节提到的转换时值类型与值类型,引用类型和引用类型之间的转换,如果是值类型与引用类型之间的转换呢
如object与int之间的转换。
1:值类型转为引用类型,首先将堆栈中值的数据复制到堆里,然后将指针传给引用类型,此步骤称为box(装箱)
2:引用类型转为值类型。根据引用指针获得数据内容,然后把堆中的数据拷贝到堆栈,此步骤称为unbox(拆箱)
显然从这里看的出box与unbox消耗大量资源,及其影响效率,所以对于未知类型的数据应该尽量用泛型,避免使用类似ArrayList等类。
参考
《applied microsoft .net framework Programming》
《Professional c#》
相关文章推荐
- 十二章 类————初始化const或引用类型要用初始化列表,隐式转换问题等,友元
- 基本数据类型的包装类型作为参数传递,以及其他引用类型作为参数传递,以及List中值的交换的一些问题
- 引用COM组件时“将类型库转换为.NET程序集失败”的解决办法
- Java中的多态,引用类型的转换
- 6、Java类、对象、构造器、引用类型内存基本知识、引用类型值传递
- 关于C#值类型,引用类型,值传递,引用传递
- C#引用类型转换的常见方式总结
- C++ 隐式和显式 初始化,类型转换
- 1.在使用new创建数组后,此时数组还是一个引用数组。 只有再创建新的对象,并把对象赋值给数组引用,到此初始化结束2.什么是引用类型?
- 关于基本类型和引用类型的值传递以及function方法的参数传递
- 面试之路(18)-java的函数参数传递类型之值传递还是引用传递
- JSP页面参数传递时类型转换总结
- 引用数据类型的转换
- 基本数据类型和引用数据类型当做参数传递
- 【Java基础】Java入门程序&基础数据类型(转换)&逻辑判断&运算等
- C#参数传递(值类型、引用类型)
- Java中引用类型变量的转换
- 黑马程序员——2.1.基础语法(关键字、常量、进制、变量、类型转换、运算符、流程控制(判断、选择、循环))
- Xmal中引用自定义的类、类型转换继承TypeConvert
- C#学习笔记(基础知识回顾)之值类型与引用类型转换(装箱和拆箱)