码迷,mamicode.com
首页 > 其他好文 > 详细

【类型转换】 隐式转换 自动提升 强制转换

时间:2017-08-28 19:57:04      阅读:179      评论:0      收藏:0      [点我收藏+]

标签:数据类型   转换   sys   操作符   类型提升   code   sof   一个   height   

基本数据类型的类型转换

Java中基本数据类型共有8种,分别是:布尔型boolean,字符型char和数值型byte/short/int/long/float/double。由于字符型char所表示的单个字符与Ascii码中相应整形对应,因此,有时也将其划分到数值型中

基本数据类型中,布尔类型boolean占有一个字节,由于其本身所代表的特殊含义,boolean类型与其他基本类型不能进行类型的转换(既不能进行自动类型的提升,也不能强制类型转换), 否则,将编译出错。

数值类型在内存中直接存储其本身的值,对于不同的数值类型,内存中会分配相应的大小去存储。相应的,不同的数值类型会有与其存储空间相匹配的取值范围。具体如下所示:
byte->【char->short->int->long->float->double
技术分享
图中依次表示了各数值类型的字节数和相应的取值范围。
在Java中,整数类型(byte/short/int/long)中,对于未声明数据类型的整形,其默认类型为int型;浮点类型(float/double)中,对于未声明数据类型的浮点型,默认为double型。


强制类型转换

当我们需要将【数值范围较大】的数值类型赋给【数值范围较小】的数值类型变量时,由于此时【可能】会丢失精度(下面说的隐式转换除外),因此,需要人为进行转换。我们称之为强制类型转换
float b = 1.5;  // 编译出错 Type mismatch: cannot convert from double to float,1.5默认是一个double型,不能自动转换为float类型
float b2 = (float) 1.5;  //  编译正确。进行强制类型转换
float b3 = 1.5f;  //  编译正确。直接用一个float类型的数值给b3初始化

double d = 0;
float f = (float) d;
int i2 = (int) f;
long l = (long) f;//注意,虽然long有64位,而float只有32位,但float->>long时也需要强制类型转换
强制类型转换时,如果超出范围较小的类型数值范围,很可能出现一些意外情况,如下:
System.out.println((byte) 127 + "   " + (byte) 128 + "   " + (byte) 255 + "   " + (byte) 256); //127   -128   -1   0
所以,在进行强制类型转换时,我们需要自己保证代码的可靠性。

隐式类型转换

jvm在编译过程中,对于默认为int类型的数值,当赋给一个比int型数值范围小的数值类型变量时(在此统一称为数值类型k,k可以是byte/char/short类型),会进行判断,如果此int型数值超过数值类型k,那么会直接编译出错,因为你将一个超过了范围的数值赋给类型为k的变量,k装不下嘛,你有没有进行强制类型转换,当然报错了;但是如果此int型数值尚在数值类型k范围内,jvm会自动进行一次隐式类型转换,将此int型数值转换成类型k。如上图中的虚线箭头。这一点有点特别,需要特别注意。
接下来我们看看如下一个较为经典例子:
byte b1 = 3;      //编译正确。如果此int型数值在数值类型byte的范围内,则jvm会自动进行一次隐式类型转换,将此int型数值转换成byte类型
byte b2 = 1000;  //编译出错 Type mismatch: cannot convert from int to byte,注意,错误的原因是"在隐式类型转换后发现超出了byte边界",所以jvm就不进行"隐式类型转换"了
byte b3 = (byte) 1000;  //  编译正确。进行强制类型转换
我们再看另一个经典例子:
byte p = 3; // 编译正确:int到byte编译过程中发生了【隐式类型转换】
int a = 3;
byte b = a; // 编译出错:cannot convert from int to byte。
byte c = (byte) a; // 编译正确。强制类型转换
byte p =3;编译正确在上面已经进行了解释,接下来将一个值为3的int型变量a赋值给byte型变量b,发生编译错误,这又是为什么呢?
区别在于前者3是直接量,编译期间可以直接进行判定,后者a为一变量,需要到运行期间才能确定,也就是说,编译期间为以防万一,当然不可能编译通过了。此时,需要进行强制类型转换。

自动类型提升

当将一个数值范围小的类型赋给一个数值范围大的数值型变量,jvm在编译过程中均将此数值的类型进行了自动提升。如上图所示,从byte到double一路都可以自动类型提升。
byte->【char】->short->int->long->float->double
float f = 5;//编译正确。整数默认是int类型,此时直接发生了【自动类型提升】
double d = 1.5f;//编译正确。float类型的浮点数赋值给double类型,此时直接发生了【自动类型提升】
long l = ‘a‘;//编译正确。字符‘a‘被当做int类型的97后赋值给long类型,此时直接发生了【自动类型提升】
在分析自动类型提升时,不要被一些虚假的表象欺骗了,如下经典案例:
long l_maxInt = 21474_83647;//编译正确。
long l_bigerThanMaxInt = 21474_83648;//编译出错:The literal ** of type int is out of range。由于数值**【超过了int类型的范围】,故而其自身已经编译出错
long l_endWithL = 21474_83648L;//编译正确。如果一个整数以字母L或l结尾,则其类型为long类型;否则为默认的int类型

int i_outOfRange = Integer.MAX_VALUE + 1;//编译正确。虽然结果溢出,但是程序没有任何问题,所以需要开发中自己留意溢出问题
如上:定义long类型的 l_bigerThanMaxInt 变量时,将编译出错,原因在于 21474_83648 默认是int类型,同时int类型的数值范围是-2^31 ~ 2^31-1(-21474_83648 - 21474_83647),因此,21474_83648 已经超过此范围内的最大值,故而其自身已经编译出错,更谈不上赋值给long型变量 l_bigerThanMaxInt  了。

不能 byte->char,char->short

由于char型其本身是unsigned型,同时具有两个字节,其数值范围是0 ~ 2^16-1,因此,这直接导致byte型不能自动类型提升到char,char到short直接也不会发生自动类型提升(因为负数的问题)。不过,byte当然可以直接提升到short等类型。
byte b = 3;
char c1=b;//编译错误:Type mismatch: cannot convert from byte to char
char c2 = ‘a‘;
short s1 = c2;//编译错误:Type mismatch: cannot convert from char to short
short s2 = b;//编译正确。自动类型提升
实际上,你可以认为"不能 byte->char,char->short"是特例,也可以认为"能char->int,char->long,char->float,char->double"是特例,就看你怎么解释了。

自动类型提升规则

注意以下讨论的是二元操作符
Java定义了若干使用于表达式的类型提升规则:
  • 所有的byte型、short型和char型将被提升到int型(例外:final修饰的short、char变量相加后不会被自动提升)
  • 如果一个操作数是long型,计算结果就是long型
  • 如果一个操作数是float型,计算结果就是float型
  • 如果一个操作数是double型,计算结果就是double型
另一种归纳方式,《Java核心技术卷I》P43:  
  • 如果两个操作数其中有一个是double类型,另一个操作就会转换为double类型。
  • 否则,如果其中一个操作数是float类型,另一个将会转换为float类型。
  • 否则,如果其中一个操作数是long类型,另一个会转换为long类型。
  • 否则,两个操作数都转换为int类型
如下示例
byte b = 50;
char c = ‘a‘;
short s = 1024;
int i = 50000;
float f = 5.67f;
double d = 0.1234;
double result = (f * b) + (i / c) - (d * s);
System.out.println("(f * b)=" + (f * b) + "  (i / c)=" + (i / c) + "  (d * s)=" + (d * s) + "  result=" + result);
//(f * b)=283.5  (i / c)=515  (d * s)=126.3616  result=672.1384
//第一个表达式 f * b 中,b被提升为float类型,该子表达式的结果也提升为float类型。
//第二个表达式 i / c 中,变量c被提升为int类型,该子表达式的结果提升为int类型。
//第三个表达式 d * s 中,变量s被提升为double类型,该子表达式的结果提升为double型。
//最后,这三个结果类型分别是float,int和double类型,想减后该表达式的最后的结果就是double类型。

自动类型提升后的精度问题

在数值类型的自动类型提升过程中,数值精度问题要分情况来看
  • 整型-->整型,自动类型提升后精度保持不变
  • float-->double,自动类型提升后精度将变高
  • 整型-->float/double,暂且定义为"精度将变低"
    这个我表示很纠结啊,按上面的节奏来说的话,应该是精度将变高(比如int转为float),但是实际上数值都可能被"消尾",也即数据都已经由"精确值"变成了"近似",那还哪来的"精度变高",很明显是"精度变低"啊?但是,怎么也找不到相应的说法。

float f = Integer.MAX_VALUE;
System.out.println(Integer.MAX_VALUE + "  " + f);//21474_83647  2.1474_8365E9(呐,被"消尾"了,已经由"精确值"变成了"近似值")
等以后找到更多更权威的资料后再补充

再来一个经典案例

进行数学运算时的数据类型自动提升与可能需要的强制类型转换
byte b = 0, b1 = 1, b2 = 2;//【隐式类型转换】
b = b1 + b2; //编译出错,Type mismatch: cannot convert from int to byte。进行 b1 + b2 运算时会先将b1和b2【自动类型提升】成为int,运算结果也是int,赋给byte类型的b1时需要强制转换(向下转型)
b = b + 0;//编译出错,同上面的错误一样,运算时会先将b【自动类型提升】成为int,运算结果也是int
b = (byte) (b1 + b2);//编译正确。【强制类型转换】
b += b2; //编译正确。【自加】没有自增类型提升问题。编译器在编译的时候自动进行了强转,相当于 b = (byte) (b + b2)

//一个奇葩的情况
final byte b3 = 3, b4 = 4;
b = b3 + b4;//编译正确。有【final】修饰的变量相加后【不会被自动提升】为int类型

//一个更奇葩的情况
final byte b6 = Byte.MAX_VALUE, b7 = 0, b8 = 1;
b = b6 + b7;//编译正确。
b = b6 + b8;//编译出错,Type mismatch: cannot convert from int to byte。注意,错误的原因和【long l = 21474_83648】一样,是因为由于数值**【超过了byte类型的范围】,故而其自身已经编译出错,而不是因为需要强制转换(向下转型)
b = 128;//编译出错,但是这里出错的原因我感觉和上面的原因是不一样的
b = (byte) (b6 + b8);//编译正确。强制转换后肯定没问题啦!
2017-8-27




【类型转换】 隐式转换 自动提升 强制转换

标签:数据类型   转换   sys   操作符   类型提升   code   sof   一个   height   

原文地址:http://www.cnblogs.com/baiqiantao/p/7442114.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!