一、自动类型提升
自动类型提升是指在程序运行时因为某种情况需要,JVM将较小的数据类型自动转换为较大的数据类型,以保证精度和正确性。在Java中,需要进行类型提升的情况有以下几种:
1. byte、short和char提升为int类型
当运算表达式为byte、short或char类型之间的运算时,Java会将它们自动提升为int类型(不会改变原值),然后再执行运算。
byte a = 3; //二进制补码:0000 0011
byte b = -2;//二进制补码:1111 1110
int c = a & b;//得到的结果默认为int类型char c1 = '0';//unicode编码\u0030 二进制00000000 00110000 十进制48
char c2 = '1';//unicode编码\u0031 二进制00000000 00110001 十进制49
int i = c1 + c2;//运算时char自动提升为int类型 运算结果的十进制为97
char c3 = (char) i;//97对应16进制为0x0061 对应Unicode字符为'a'
System.out.println(c3); //打印结果:a
为什么位数低于int的数值类型和字符类型在运算时jvm会对其进行类型提升?
1. 避免精度丢失或溢出的问题
2. 使用较小类型运算没有性能优势, JVM设计时计算机主流架构是32位,对于CPU来说,无论是8位的运算还是32位的运算,都是在一个时钟周期内完成的,使用较小类型并不能节省时间。
2. 较小数值类型提升为较大范围数值类型
当运算表达式中包含不同类型的数据,例如int类型和double类型,为了避免数据类型的不匹配,Java会将其中较小范围数据类型自动提升为另一个较大范围的数据类型,然后再执行运算。
int i = 3;
double j = 4.0;
//运行时先将i转换为double类型3.0
double l = i + j;//得到的结果默认为double类型
3. 实参提升为方法形参类型
当调用方法时,如果传递的参数类型与方法定义的参数类型不匹配,JVM会自动进行类型提升或类型转换(注意只能自动进行基础数据类型提升或子类向父类提升),以使参数类型与方法定义的参数类型相匹配。这种情况常见于一个通用的功能方法,形参为父类,但调用时可以传进其各个子类的对象作为实参,执行时会将对象提升为父类类型,但注意这只是改变引用的类型,其实际指向的对象仍然没有变,因此在方法中调用对象的属性或方法时仍然执行的是子类中重写的,以此实现对应细分的功能。这就体现了Java的多态性。
类型提升是在JVM运行时字节码指令执行阶段进行的,当执行字节码指令时,JVM会根据指令的类型和操作数的类型来进行类型提升。类型提升的目的是保证运算的正确性和精度,避免数据类型不匹配、精度丢失和溢出等问题。同时,类型提升也可以提高代码的可读性和可维护性,使程序更加健壮和可靠。需要注意的是,类型提升可能会增加运算的开销,因此在设计程序时应该尽可能避免无必要的类型提升。
二、强制类型转换
强制类型转换是指程序员在代码中使用类型标识强制将一个对象的类型转换为其他类型,它与自动类型提升的区别如下:
-
触发条件:类型提升是在Java虚拟机中自动进行的,通常发生在两个不同数据类型的运算中;而强制类型转换需要程序员在代码中显式地指定,通常发生在数据类型不匹配的情况下。
-
数据类型的变化:类型提升通常是将一个较小的数据类型自动转换为一个较大的数据类型,以保证数据的正确性和精度;而强制类型转换则可以将一个数据类型强制转换为另一个数据类型,但这可能会导致数据的精度丢失或溢出。
-
是否安全:类型提升是自动进行的,通常是安全的,不会导致数据的精度丢失或溢出;而强制类型转换需要程序员自己负责,如果转换不当可能会导致数据的精度丢失或溢出,或者抛出无法转换的异常,从而引发程序错误。