byte、short、char、int等类型变量在作为操作数时的类型自动转换(含final修饰符)和其他延伸问题
最近在牛客网看到一道题,做错了,很是遗憾,所以在本贴上对相关知识点进行一个次总结。
问题:
(一)当操作数只含有byte
,short
,char
,int
等类型时进行计算的过程中,类型被自动转换的问题(包含final
修饰符的情况)
(二)当操作数含有其他数据类型(如long
,float
,double
等类型时…)进行计算时,类型被自动转换的问题
(三)对byte
类型变量赋值在常量方面进行测试
(四)探讨a = a +1和a+=1的区别
测试
Java代码:
void statu1(){
/************************不存在final的情况下*********************/
byte byte_1 = 1,byte_2 = 2,byte_3 = 3;
char char_1 = '1',char_2 = '2',char_3 = '3';
short short_1 = 1,short_2 = 2,short_3 = 3;
int int_1 = 1,int_2 =2;
double double_1 = 1;
float float_1 =1;
long long_1 =1;
//操作数属于byte,short,char,int内的计算
//赋值语句左边不为int型
byte_3 = (byte)(byte_1 + byte_2);
short_3 = (short)(short_1 + short_2);
char_3 = (char)(byte_1 + short_2);
//赋值语句左边为int型
int_1 = byte_1 + byte_2;
int_1 = byte_1 + char_2;
int_1 = short_1 + int_2;
//操作数含long,float,double的计算
double_1 = double_1 + byte_1;
long_1 = short_1 + byte_1;
float_1 = long_1 + byte_1;
}
void statu2(){
/************************存在final的情况下*********************/
final byte bytef_1 = 1,bytef_2 = 2;
final char charf_1 = '1',charf_2 = '2';
final short shortf_1 = 1,shortf_2 = 2;
final int intf_1 = 1,intf_2 =2;
final double doublef_1 = 1,doublef_2 = 2;
final float floatf_1 = 1,floatf_2 = 2;
byte byte_1 = 3,byte_2 = 4;
char char_1 = '3',char_2 = 4;
short short_1 = 3,short_2 = 4;
int int_1 = 3,int_2 =4;
float float_1 = 1,float_2 = 2;
double double_1 = 1,double_2 = 2;
//操作数属于byte,short,char,int内的计算
//部分操作数被final修饰
byte_2 = (byte) (charf_1 + char_1);
int_2 = charf_1 + char_1;
char_2 = (char) (shortf_1 + byte_1);
int_2 = shortf_1 + byte_1;
//所有操作数被final修饰
byte_2 = charf_1 + bytef_2;
byte_1 = intf_1 + intf_2;
int_1 = bytef_1 + shortf_1;
float_1 = shortf_1 + charf_2;
double_1 = bytef_1 + intf_2;
//操作数存在高位类型(long ,float ,double)计算
//操作数类型相同
double_2 = doublef_1 + doublef_2;
double_2 = floatf_1 + floatf_2;
float_2 = floatf_1 + floatf_2;
//操作数类型不相同
float_2 = floatf_1 + intf_2;
double_2 = floatf_1 + intf_2;
double_2 = floatf_1 + bytef_2;
}
分析:
- 以上代码中,凡是能出现既是不出现编译错误。没有显式强制转换类型意味着已经进行了隐式类型转换。
最终结论:
影响因素和原则:
这里存在多个可变因素:
- 赋值语句的变量类型是否属于int,byte,short,char等变量
- 赋值语句左边的数据类型是什么
- 赋值语句的数据类型是否被final修饰
遵守原则:
- Java中整数值默认为Int类型 (浮点数默认为double类型)
- Java表达式转换规则,由低向高转换
- final所修饰的变量不隐式转换,因为所修饰的变量不可变。
注意:
(要区分两种转换)
- 计算之前的操作数的数据类型转换
- 计算之后得到的计算结果的数据类型转换
总结:
操作数为byte,short,char,int类型范围计算,遵守整数值为int型:
没有final修饰的情况下:
①当操作数为byte
,short
,char
,int
型范围内,遵守整数值为int型,整数值在作为操作数时都将默认隐式转换为int
型,然后再进行计算,计算结果也为int
类型.存在final修饰变量的情况下:
①部分操作数被final修饰:计算结果都是int类型,等于同无final的情况,所以如果赋值语句左边为byte,short,char,必须强制转换,比如byte = (byte)(final int + byte)
,byte = (byte)(final char + byte)
计算结果都为int,被强制转换为byte.
② 所有操作数被final修饰:所有操作数变量都不可以,都无法隐式转换,此时计算结果可以任意类型,不遵守类型转换低向高原则,全看赋值语句左边为什么类型.比如byte = final char +final byte
计算结果转换为byte,double = final int + final char
计算结果转换为double ,long = final byte + final byte
计算结果转换为long ,float = final byte +final byte
计算结果转换为float.等号左边变量类型为什么类型,计算结果便被隐式转换为什么类型。
存在
操作数存在高位类型(long ,float ,double)计算:
没有final修饰的情况下:
①Java表达式转型规则由低向高转换,如果有一个操作数为高位型,计算结果也为高位,如byte+int
,计算结果为int
。int+long
,计算机结果为long
。double+long
,计算结果为double
(高低位的意思是数据的范围,范围越小则低,越高则高)存在final修饰变量的情况下:
①操作数类型相同:计算结果为同级别的类型,如final double + double
计算结果为double,final double + final double
,计算结果为double,float + float
计算结果为float
②操作数类型不相同:计算结果为最高级的类型,如final long + final double
计算结果为double ,long + final double
计算结果为double,final float + double
计算结果为double ,final float+ final byte
计算结果为float
所以在含有long,float,double类型计算时,与有无final修饰符合final是否修饰所有操作数无关,有没有都遵守Java转换原则,低向高转换,可以理解为有final修饰符只对byte,short,char,int类型范围的计算有影响
注意:
这里所有的结论都存在一点问题,就是博主我暂时还没有弄清楚两个问题,因为不确定,所以表述的时候可能会捎带模糊,望清楚的朋友看到可以留言解答一下。适时我会对本博进行更改。
- 在byte,short,char,int类型范围内作为操作数计算的时候,自动类型转换是在计算之前就将类型转换为int型,还是计算之后将结果转换成Int型,实现的逻辑过程是怎么样?
- 在包含float,long,double等类型作为操作数计算的时候,数据的类型转换是计算之前将操作数转换还是在计算之后将结果的类型转换?
- 被final修饰操作数的情况下,变量不可变,那么类型转换是通过什么方式进行?是计算之后将结果根据等号左边的变量类型进行转换的吗?是由怎么样的机制实现的?
希望了解的朋友可以留言告诉我,谢谢!!感激不尽!!
测试延伸
Java代码(一):
//byte的值的范围为-127~127,所以常量值结果在127范围内,依然是byte,但是计算结果超过127,就为Int类型
//需要强制转换
byte b9 = 3+3;
byte b10 = (byte) (127+3);
System.out.println("b9="+b9);
System.out.println("b10="+b10);
输出结果:
b9=6
b10=-126
分析:
- 当赋值语句的左边为
byte
类型,右边为两个变量时,就要参考上面的的情况,因为byte
的数据范围有限,是-127~127
,虚拟机无法马上得知两个变量的值是否已经超过了byte
类型的范围,所以需要强制转换为byte
类型才能赋值给左边。 - 当赋值语句的左边为
byte
类型,右边为两个常量时,在编译时就已经知道结果了,如代码所示,b9 = 3 + 3
,相当于b9 = 6
的效果,但是也有些情况要注意,如果常量的值处于byte
类型的数据范围(-127~127),则不需要强制转换(如3+3
),如果超过了则需要强制转换(如127+3
),相当于b9 = (byte)130
- byte类型的数据超过127时的强制转换的结果的运算逻辑参考网上,目前本博客不做出讨论。
Java代码(二):
final byte fa=1;
final byte fb=2;
byte b9 = fa + fb;
分析:
发现被final修饰之后的byte变量相加赋值给byte类型是可以编译通过的,并不会报错,这是为什么呢?从上一段测试中,我们可以得知,常量相加,在编译时已经知道了结果,相当于byte变量被赋值了一个数值。这里的变量被final修饰之后,对于Java而言,就相当于这两个变量已经成为了常量。所以不会报错。
Java代码(三):
byte b1=1,b2=2;
b1 = (byte) (b1 + 1);
b2 += 2;
分析:
以上是两种情况:
- 第一种是使用通常的+号运算符
- 第二种使+=运算符。
在第一种情况下,两个byte变量相加,操作数会被提升为int型再计算,所以计算结果是int类型,赋值给一个byte的变量,就必须使用显示强制类型转换,不然会报编译错误,类型不同,不允许赋值。
在第二情况下,不需要强制转换是不会报错的,为什么呢?是因为使用+=类似运算符进行计算的时候,是会将运算结果隐式强制转换等于等号左边变量的类型的。我们反编译一下编译之后的代码就可以看到。
byte b1 = 1;byte b2 = 2;
b1 = (byte) (b1 + 1);
b2 = (byte) (b2 + 2);
代码中的+=运算符在编译之后,实际的效果等于第一种情况,在编译时是会给运算结果加一个强制类型转换的。
参考博客:
byte类型运算细节
java中byte类型数据的运算
关于被final修饰的基本数据类型一些注意事项
当然还有牛客网里大佬的解答。thanks
在此对参考过的网站和博客的作者表示感谢!!