面试回答
假如,我们要用 Math.abs对一个 Integer 取绝对值的时候,如果用以下方式:
System.out.println(Math.abs(Integer.MIN_VALUE));//-2147483648
得到的结果可能是一个负数。原因要从 Integer 的取值范围说起,int 的取值范围是 -2^31 —— (2^31)-1,即 -2147483648 至 2147483647。
那么,当我们使用 abs 取绝对值的时候,想要取得 -2147483648 的绝对值,那应该是 2147483648。但是,2147483648 大于了 2147483647,即超过了 int 的取值范围。这时候就会发生越界。
2147483647 用二进制的补码表示是:01111111 11111111 11111111 11111111
这个数 +1 得到:10000000 00000000 00000000 00000000
这个二进制就是 -2147483648 的补码。
虽然,这种情况发生的概率很低,只有当要取绝对值的数字是 -2147483648 的时候,得到的数字还是个负数。
那么,如何解决这个问题呢?
既然是因为越界了导致最终结果变成负数,那就解决越界的问题就行了,那就是在取绝对值之前,把这个 int 类型转成 long 类型,这样就不会出现越界了。
大家可以执行下以下代码:
System.out.println(Math.abs((long) Integer.MIN_VALUE));//2147483648
得到的结果就是:
2147483648
知识扩展
整型的取值范围
Java 中整型主要包含 byte、short、int 和 long 这四种,表示的数字范围也是从小到大的,之所以表示范围不同,主要和他们存储数据时所占的字节数有关。
先来个简答的科普,1字节=8位(bit)。java 中的整型属于有符号数。
先来看计算中 8bit 可以表示的数字:
最小值:10000000(-128)(-2^7)最大值:01111111 (127)(2^7-1)
整型的这几个类型中:
- byte:byte 用 1 个字节来存储,范围为 -128(-2^7)到127(2^7-1),在变量初始化的时候,byte 类型的默认值为0。
- short:short 用 2 个字节存储,范围为 -32,768(-2^15)到32,767(2^15-1),在变量初始化的时候,short 类型的默认值为 0,一般情况下,因为Java本身转型的原因,可以直接写为 0。
- int:int 用 4 个字节存储,范围为 -2,147,483,648(-2^31)到 2,147,483,647 (2^31-1),在变量初始化的时候,int 类型的默认值为 0。
- long:long 用8个字节存储,范围为 -92,233,72,036,854,775,808(-2^63)到9,223,372,036,854,775,807(2^63-1),在变量初始化的时候,long 类型的默认值为 0L 或 0l,也可以直接写为 0。
超出范围怎么办
上面说过了,整型中,每个类型都有一定的表示范围,但是,在程序中有些计算会导致超出表示范围,即溢出。如一下代码:
int i=Integer.MAX_VALUE;
int j=Integer.MAX_VALUE;
int k=i+j;
System.out.println(k);
输出结果:2
这就是发生了溢出,溢出的时候并不会抛异常,也没用任何提示。所以,在程序中,使用同类型的数据进行运算的时候,一定要注意数据溢出的问题。