数据类型(2) - 类型转换

类型转换分为三种,一种是值类型之间的,一种是引用类型之间的,而最后一种则是值类型和引用类型的相互转换。

值类型之间的转换比较简单,通常是数字的转换。而c#的可以代表数字的若干类型的区别仅仅是其取值范围不同,例如short,int,long之类。此时如果要将取值范围较小的数据类型转为取值范围较大的类型,则一般一定会成功(我想不出失败的理由),无需写出类型名称,直接就可以完成隐式转换。例如将Short转为int。但如果反过来将int转为short,则隐式转换一定会失败,编译器会通知我们这个转换必须使用显式转换。此时我们需要在括号中显式指出转换类型名称(即使你知道转换一定会成功):

            int aa = 0;
            short bb = (short) aa;

显式转换是强制的,所以如果当实际上转换不能成功时(例如将65537转换为short),将会保存溢出的值。比如将65537转换为short,你将会得到值1。默认情况下,溢出不会抛出异常。如果你想捕捉可能的溢出并进行处理,可以使用checked关键字,括住要检查的转换语句,或者{}也可以。此时如果转换出现溢出,则会抛出异常。可以用try-catch处理异常。Visual studio在项目属性中build的advanced中,提供了check for arithmetic overflow/underflow一项,勾选它意味着自动为所有的转换运算加上check。我们无需一个一个自己加。

当然,如果你启用了check for arithmetic overflow/underflow,但对于某一块代码不想抛出异常,你可以用unchecked关键字包住这块代码。因为不抛出异常是编译器的默认行为,所以unchecked关键字只有在全局启用了check for arithmetic overflow/underflow才显得有用。

引用类型之间的转换也很常见。对于父类,子类之间的继承,我们可以类比值类型的short和int。但情况比值类型来说要稍微难懂一些。比如假设我们有一个类rectangle(构造函数吃三个变量),我之前曾经对于下面这行代码完全无法理解:

object c = new rectangle("", 1, 2);

那么c到底是什么类型呢?假设类rectangle有一个方法area,返回长方形的面积,那么我们可以试图调用c.area,此时编译器报错,我们看到其实c是不存在这个方法的,所以c应该是object类型。但我调用c.GetType(),返回的却是rectangle。那么这行代码执行之后,究竟发生了什么事情?实际上是这样的:

首先,c是object类型这个肯定没有问题(否则c将拥有所有rectangle的方法,而实际上没有)。当执行到new之前,系统在栈上分配一块地盘,为c的引用。(此时还没有指针)执行new的时候,系统在堆上分配另外一块地盘(其大小等于rectangle所有值类型属性+引用类型属性的大小之和),然后将栈上的指针指到堆上这块地盘上去。而GetType()返回的类型,并不是栈上那块引用的类型,而是这个栈指向的堆上那块地盘的类型。此时,由于引用本身和指针指向的终点的类型不同,但前者较大,所以隐式转换没有问题。

那么问题来了,如果我反过来如何呢?

rectangle d = new object();

猜也能猜得出,这显然是不行的。如果你打算显式转换的话,你仍然可以通过指定转换类型来完成:

            object x = new object();
            rectangle y = (rectangle)x;

不过这次和值类型不一样,如果失败了的话,编译器可不知道怎么处理溢出(实际上溢出的概念是专指数字的),所以将会爆出运行时错误!try-catch当然是一个解决方案,但c#还提供了as关键字进行快速检测:

rectangle d = x as rectangle;

此时如果d的值为null,则意味着转换失败。你可以在其后进行处理,并不会抛出任何异常。

值类型和引用类型的相互转换被称为装箱和拆箱。根据之前所讲,这种转换肯定是最复杂的,因为两种类型的组件个数都不同。所以,当值类型转换为引用类型(装箱)时,我们要在堆上额外分配空间,还要加一个指针。具体点说就是:

  1. 计算应该在堆上分配内存的大小,注意这个大小包括了额外的指针
  2. 在堆上分配内存
  3. 返回值类型的地址(现在栈上的值类型变成了对堆上的对象的一个引用)

拆箱较为简单:

  1. 获得目标对象在堆上的所有属性的地址
  2. 将这些属性包含的值(通过地址获得)复制到栈上的值类型实例之中
int i=0;
System.Object obj=i;
Console.WriteLine(i+","+(int)obj);

这个例子中一共发生了2次装箱和一次拆箱。拆箱是第三行将obj转换为int类型,2次装箱都发生在WriteLine方法中。当试图构建一个字符串时,系统隐式的调用了concat方法,其所有的变量都是object。所以i和(int32)obj全部都需要装箱。

注意“,”已经是一个字符串,而字符串是引用类型。引用类型永远是装箱的所以不需要再次装箱。

装箱和取消装箱都是需要大量运算的过程。 对值类型进行装箱时,必须创建一个全新的对象。 此操作所需时间可比简单的引用赋值操作长 20 倍。 取消装箱时,强制转换过程所需时间可达赋值操作的四倍。(http://msdn.microsoft.com/zh-cn/library/ms173196.aspx)在Array这种你可以往里面放任何东西的对象集合中,所有的成员都是object,遍历他并进行修改可能的装箱拆箱次数非常大,性能会受到严重的影响。c#在2.0版本提出了泛型以取代这种弱类型集合对象(DataTable是另外一个例子)。

时间: 2024-07-29 05:56:25

数据类型(2) - 类型转换的相关文章

一、数据类型和运算符——5-基本数据类型的类型转换

5-基本数据类型的类型转换 1.自动类型转换 2.强制类型转换 3.表达式类型自动提升

引用数据类型的类型转换(学习笔记)

引用数据类型的类型转换 引用数据类型也能够做类型转换 (1)引用数据类型的转换是有条件,不能够随便转 (2)转换的条件是:只能够在有继承关系的类型间进行 (3)正因为只能沿着继承树进行转换,才有向上转型和向下转型的概念 向上转型 1.把子类对象交给父类的引用---自动类型转换 ★ 当我们拥有了一个父类引用的时候,就不能再简单的认为它指向父类对象了,它还有可能指向任意一个子类对象 父类的引用指向子类对象是没有问题的,不过只能看到对象身上来自于父类的属性和行为 向下转型 1.把父类对象交给子类引用-

Java基本数据类型与类型转换

Java基本数据类型与类型转换 文本关键字:8种.基本数据类型.整数类型.浮点类型.字符类型.布尔类型 一.基本数据类型 1. 概述 在Java中,所使用到的类型可以分为两大类,一类是基本数据类型,一共有8种,包含:整数,小数,字符,布尔.另外一类是引用类型,包含:字符串,数组以及各种Java类. 2. 整数类型 整数类型是一个很常用,也比较简单的类型,在计算机中以二进制的方式存储,其中有一位是符号位. byte:-2^7 ~ 2^7 - 1 1字节 8bit short:-2^15 ~ 2^1

java注释 命名 数据类型 基本类型转换 位运算符 逻辑运算符 三目运算符

一.java注释 1.单行注释  //注释内容 2.多行注释 /*注释内容*/ 3.文档注释(可用javadoc工具生成api文档,不过我还没试过)/**文档注释*/,文档注释可以在使用的时候看见注释. 文档注释常用的标记 @auther作者 @version版本 @deprecated 不推荐使用 @param 本放的参数 @return 返回值 @throws异常,同@exception 二.java的命名 1.项目名 字母全部小写 2.包名 全部小写 3.类名 首字母大写加驼峰 4.方法名

java基础学习总结二(标识符、字符集、数据类型以及类型转换)

一:标识符 1:标识符可以由字母.数字.下划线_.$符等组成2:标识符的首字母只能是字母.数字.下划线3:标识符不能使用关键字或者保留字4:标识符可以是中文,但是不建议使用中文5:标识符可以任意长,没有限制. 二:字符集 ISO8859-1:标准字符集,西方国家都在使用BIG5:台湾地区使用GB2312:大陆地区最早使用(简体字符集)GBK:在gb2312基础上的扩展,包括简体字和繁体字GB18030:包括简体字.繁体字.藏蒙维吾尔等少数民族语言等 三:数据类型 数据类型分为基本数据类型和引用数

知识点一主函数、数据类型、类型转换

一.主函数的内容 输出,输入 输出:Console.WriteLine();Console.Write();1.输出数字 Console.WriteLine(22); //22Console.WriteLine(12+44); //562.输出文字Console.WriteLine("abc");//abcConsole.WriteLine("78"+"56");//78563.整合输出Console.WriteLine("78+56=

Javascript数据类型和类型转换

Javascript数据类型 Boolean(布尔).Number(数字).String(字符串).Undefined(未定义).Null(空对象).Object(对象类型).Function 引用类型:对象.数组.函数. 原始数据类型:数值.布尔值 .null .字符串 原始类型的变量不能动态添加成员: <script type="text/javascript"> var n='我好帅'; n.Age=100; alert(n.Age);//结果是undefined &

js的数据类型及类型转换

Js中的数据类型一共有六种,即number,string,boolean,underfine,null,object. 通常,我们判断变量的数据类型会用到typeof()方法. 数据的转换分为显式类型转换和隐式类型转换,我们经常用到的是将变量转换成字符串或数字.  一:显式类型转换: 1.转换成字符串时: toString() 1 var str= abc; 2 alert(str.toString()); 2.转换成数字时: (1)parseInt() 转换成整数,parseFloat()转换

数据类型 数据类型转换 运算符

鉴别空对象看齐能否进行属性操作. 双等会进行隐式类型转换,==两侧数据类型不一样时,会转换成一样的在进行比较. 1 若等号一侧为 布尔值 就都转换成布尔值进行比较. NaN和任何内容比较结果都为false onchange检测内容(在表单中):1 在单选和复选框中,检测checked值是否发生变化(检测是否勾选或取消勾选) 2在其他表单控件中,检测value值发生变化. 3 表单控件(input textareea selecter)要获取他们的值获取的是value. 在js中只有nan类型的数

1221——visual2012基本操作、数据类型、类型转换

基本操作 //输出 Console.WriteLine("这是一行文字");自动回车. Console.write("Hello world ");不带回车. 注意: 1.大小写敏感.(快捷键Alt +→) 2.括号,引号,分号都是英文状态下的符号. 3结尾不要忘记写分号. //输入 string s =Console.ReadLine(); 如何拼接字符串. Console.WriteLine("您的用户名是" + u + ",密码是