【Java】基本数据类型 - 基本数据类型的类型转换

Posted by 西维蜀黍 on 2019-06-28, Last Modified on 2021-10-02

基本数据类型

序号 数据类型 大小/位 封装类 默认值 可表示数据范围
1 byte(位) 8 Byte 0 -128 ~ 127
2 short(短整数) 16 Short 0 -32768 ~ 32767
3 int(整数) 32 Integer 0 -2147483648 ~ 2147483647
4 long(长整数) 64 Long 0L -9223372036854775808 ~ 9223372036854775807
5 float(单精度) 32 Float 0.0F 1.4E-45 ~ 3.4028235E38
6 double(双精度) 64 Double 0.0D 4.9E-324 ~ 1.7976931348623157E308
7 char(字符) 16 Character 0 ~ 65535
8 boolean 8 Boolean flase true或false

基本数据类型的类型转换

自动类型转换

自动类型转换,也称隐式类型转换,是指不需要书写代码,由系统自动完成的类型转换。由于实际开发中这样的类型转换很多,所以 Java 语言在设计时,没有为该操作设计语法,而是由 JVM 自动完成。

转换规则:从存储范围相对小的类型转换成存储范围相对大的类型。

具体规则为:byte→short(char)→int→long→float→double

也就是说 byte 类型的变量可以自动转换为 short 类型。注意,这里的“自动转换”,指的是不需要开发者显式地声明转换过程,而完全又JVM自动实现转换。

示例代码:

byte b = 10;
short sh = b;

这里在赋值时,JVM 首先将 b 的值转换为 short 类型,然后再赋值给 sh。


在类型转换时可以跳跃。示例代码:

byte  b1  =  100;
int  n  =  b1;

注意问题:在整数之间进行类型转换时,数值不发生改变,而将整数类型,特别是比较大的整数类型转换成小数类型时,由于存储方式不同,有可能存在数据精度的损失。

强制类型转换

强制类型转换,也称显式类型转换,是指必须书写代码才能完成的类型转换。该类类型转换很可能存在精度的损失,所以必须书写相应的代码,并且能够忍受该种损失时才进行该类型的转换。

赋值运算的自动转换规则

转换规则:从存储范围大的类型到存储范围小的类型。

具体规则为:double→float→long→int→short(char)→byte

语法格式为:(转换到的类型)需要转换的值

示例代码:

double d = 3.10;
int n = (int)d;

这里将 double 类型的变量 d 强制转换成 int 类型,然后赋值给变量 n。需要说明的是小数强制转换为整数,采用的是“去 1 法”,也就是无条件的舍弃小数点的所有数字,则以上转换出的结果是 3。整数强制转换为整数时取数字的低位,例如 int 类型的变量转换为 byte 类型时,则只去 int 类型的低 8 位(也就是最后一个字节)的值。


示例代码:

int  n  =  123;
byte  b  =  (byte)n;
int  m  =  1234;
byte  b1  =  (byte)m;

则 b 的值还是 123,而 b1 的值为-46。b1 的计算方法如下:m 的值转换为二进制是10011010010,取该数字低8位的值作为b1的值,则b1的二进制值是11010010,按照机器数的规定,最高位是符号位,1 代表负数,在计算机中负数存储的是补码,则该负数的原码是 10101110(11010010的补码为原值-1,即11010001,则其补码的反码为,10101110),该值就是十进制的-46。

注意问题:强制类型转换通常都会存储精度的损失,所以使用时需要谨慎。

类型提升(Type Promotion)

所谓类型提升(Type Promotion),就是指在多种不同数据类型的表达式中,类型会自动向范围表示大的值的数据类型提升。

long count = 100000000;
int price = 1999;
long totalPrice = price * count;

price 为 int 型,count 为 long 型,运算结果为 long 型,由于将运算结果赋值给了一个long类型,因此运算结果正常,没有出现溢出的情况。


而如果是下面的情况,就会出问题:

int count = 100000000;
int price = 1999;
long totalPrice = count * price;

编译没任何问题,但结果却输出的是负数,这是因为两个 int 相乘得到的结果是 int, 相乘的结果超出了 int 的代表范围。这种情况,一般把第一个数据转换成范围大的数据类型再和其他的数据进行运算。

总结

Java定义了如下的自动提升规则:

  • 当运算符为取正运算符(+)。取负运算符(-)或按位取反运算符(~)时,如果任一操作数的类型为byte、char或short,则先被转换为int,再参与运算,运算结果的类型为int;
  • 整个算术表达式的数据类型自动提升到表达式中最高等级操作数同样的类型,比如:
    • 如果运算符任意一方的类型为double,则(在执行运算前)另一方会被自动转换为double类型,且运算结果也为double类型;
    • 如果运算符任意一方的类型为float,则(在执行运算前)另一方会被自动转换为float类型,且运算结果也为float类型;
    • 如果运算符任意一方的类型为long,则(在执行运算前)另一方会被自动转换为long类型,且运算结果也为long类型。
public static void main(String[] args)  
{  
    // 下面2行代码出错,shortValue类型参与运算,类型自动提升到int  
    // 将一个int类型的值赋给一个short类型的值,编译不过  
    short shortValue = 5;  
    shortValue = shortValue - 2;  
  
    // 下面4行代码正确,3个不同类型的值参与运算,类型提升到最高的类型  
    // double,int,byte中,double类型最高,所以结果double类型  
    byte byteValue = 4;  
    int intValue = 1;  
    double doubleValue = 2.33;  
    double result = byteValue + intValue + doubleValue;  
    System.out.println(byteValue + intValue + doubleValue);  
    // 下面代码的类型同样为double  
    System.out.println(doubleValue / intValue);  
}

Reference