浅谈Java数据类型中byte、short、int和long之间的转换规则

最近在b站补习一些Java的基础知识,受很多人的推荐,看了动力节点官方的一套零基础Java教程,看了几集发现自己对于一些很细节的东西,平时都没怎么注意,听老师详细的讲解之后来做一下笔记。

Java整数型数据类型介绍

首先介绍一下Java中整数型数据类型中的四种类型,分别是byte型、short型、int型和long型。如下表,取值范围用具体数字表示便于后续变量的取值。

整数型数据类型 默认值 占用空间大小(字节) 取值范围
byte 0 1 -128~127
short 0 2 -32768~32767
int 0 4 -2147483648 ~2147483647
long 0L/l 8 -9223372036854775808 ~9223372036854775807

当然这个范围的具体值实在太难记了,平时要用的话还是百度或者用占用空间的字节长度推吧。在听课的时候听到一个整数数据类型间转换的规则:

1.Java中的整数字面类型默认被当作int型处理,当要被当作long类型来处理的话,要在字面值后添加l(小写)或L(大写)。建议大写L,因为在编译器敲除来很难分辨1和l,会容易搞错。
2.在不同数据类型做运算时,Java中小容量(如int)可自动转换成大容量(如long),称为自动类型转换机制。
3.但大容量转小容量要用强制类型转换符。

下面举例浅谈一下这些类型的转换规则。

  1. long和int之间的转换
//int转long
int a = 2147483648;	//编译报错

//long类型错误声明赋值方式
long b0 = 10;	//编译没报错,10是int型的字面值
long b1 = 2147483648;	//编译报错
//long类型正确声明赋值方式
long b3 = 10L;
long b4 = 2147483648L;

//int和long的运算
int c=1;
System.out.println(b4+c);	//输出正确答案2147483649
  • 因为int类型的取值范围为-2147483648 ~2147483647,当执行语句int a = 2147483648时由于赋值号右边默认是int的字面值,而2147483648已经超过了int可以表示整数的范围,会编译报错:“错误: 过大的整数:2147483648”。所以自动类型转换只会在int转long或它们进行运算的时候自动转换。
  • 在声明赋值long类型时,你要赋值的整数字面值后如果没有加L,如“long b1 = 2147483648;”会编译报错:“错误: 过大的整数:2147483648”,说明2147483648还是int型字面值。但“long b0 = 10;”不会报错因为10还在int的范围内,但10会从int型自动转换成long型。b3和b4的声明赋值语句没有报错,因为其后加了L,b3和b4就都是long类型且在long的范围内。
//long转int
long a = 2147483648L;	//a为long类型
int b = (int)a;	//强制类型转换
System.out.println(b); //输出结果:-2147483648
  • 上述代码先声明了long类型的变量a并赋值2147483648,这个值已经超出了int的取值范围。
  • 然后再声明int类型的变量b,将a强制类型转换并赋值给b,按照常理来说b应该是2147483648,但输出结果却是-2147483648,这就是强制类型转换经常出现的“精度损失”。
    浅谈Java数据类型中byte、short、int和long之间的转换规则_第1张图片
  • 从上图可以看出来,强制转换后将原本long类型左边多于的4个字节砍掉了,然后转换成右边只有4个字节的int型。那为什么强制转换后是-2147483648呢?

这就涉及到计算机底层的知识了(计算机组成原理)。因为计算机里只有加法器,没有减法器,所有的减法运算里只可以转换为加法进行。用补数代替原数就可以把减法转换为加法。出现的进位就是模,此时的进位可以忽略不计。二级制下,有多少位数参加运算,模就是在1的后面加上多少个0。而补码就是按照这个要求来定义的:正数不变,负数即用模减去绝对值。

  • 上面的话让人一下子看不懂,总而言之,计算机中二级制一共有三种表示形式:原码、反码、补码;而计算机在任何情况下底层表示和存储数据的时候都是采用补码形式
  • 正数的补码:与原码相同。
    负数的补码:负数的绝对值对应的二级制码所有二级制位取反,再加1。
  • 当然也可以由补码求原码,反过来推就是了。而上述强制转换就是已知补码求原码的过程。
    补码:10000000 00000000 00000000 00000000(负数)
    减1:01111111 11111111 11111111 11111111
    取反:10000000 00000000 00000000 00000000
    但由于补码是负的,于是10000000 00000000 00000000 00000000的原码去了绝对值后十进制为-2147483648。
  • 但这个数据只是刚刚好卡在int型的边界后,显得赋值和输出差距不大,但如果在long型的左边4个字节还有数据的话,如果砍掉了,最后输出的结果就会和赋值的数据相差非常大,会造成灾难性的后果,程序员要谨慎使用强转符
  1. byte类型
byte a = 50;
byte b = 127;
byte c = 128;	//编译报错
  • 上面a和b没有编译报错,而128却编译报错了。说明什么?
  • 说明byte不遵循我刚刚开始所说的第一条原则:“Java中的整数字面类型默认被当作int型处理”。因为显然128是在int型的范围内的,这样是不会报错的。但报错了就说明SUN公司最开始就把byte类型的声明定义为默认按照byte类型而不是int类型处理,于是定义就不用强转符。因为byte型的取值范围为-128~127,而128刚好超过了这个范围,于是“byte c = 128;”编译报错。
byte d = (byte)128;
System.out.println(d); //输出结果:-128
  • 如果把128强制转换为byte型,则会结果也会和上面一样有精度损失。
    浅谈Java数据类型中byte、short、int和long之间的转换规则_第2张图片
  1. short类型
    经过代码测试,short类型和byte类型是一样的,也是由SUN公司最开始就把short类型的声明定义为默认按照byte类型而不是int类型处理。
short a=32768;	//编译报错
short b=(short)32768;	
System.out.println(b);	//输出结果:-32768
  1. char类型
    为什么我要说char类型呢,因为我发现char类型的取值范围是0~65535,我就用代码试了一下。
char cc = 65535;	//在范围内不报错
cc = 65536;	//编译报错,在范围外

所以尽管是char类型的,就算把整数赋值给cc也是可以的,但超出范围会提示“不兼容的类型: 从int转换到char可能会有损失”。

  1. 结论
    综上所述:当一个整数字面值没有超出byte、short、char的取值范围,这个字面值可以直接赋值给byte、short、char类型的变量,这种机制SUN公司允许了,目的是为了方便程序员的编程。当整数字面值超过了byte、short、char的取值范围,赋值要用强制类型转换符,不过有可能会造成精度损失!

你可能感兴趣的:(笔记)