原码、反码、补码、移码区别与应用

一、Java中的基本数据类型

Java中共有8种数据类型,分为三大类。
字符型:char
布尔型:boolean
数值型:1. 整型:byte、short、int、long;2. 浮点型:float、double
String不是基本数据类型,是引用类型。

在这里插入图片描述


关注点1:基本类型默认值0

从表中可以看到基本数据类型的起始默认值都是0,但是每个之间都有区别。例如,char默认值是单引号'\u0000'表示NUL(空的不可见字符),其码值是0
boolean类型的默认值是false,在JVM中仍然使用ICONST_0字节码指令赋值,即常数0

boolean b = false;
1: iconst_0
2: istore_1

关注点2:开发的时候注意数据溢出问题

数据溢出的时候并不会报错,也没有任何提示。

int i = 2147483647;
int j = 1;
System.out.println(i + j); 
运行结果:-2147483648

因此需要开发人员在同类型数据运算时,注意数据溢出的问题,并避免编写容易导致溢出的代码。

int mid = (i + j) / 2;
替换为
int mid = i + (j - i) / 2;

关注点3:不同类型不能自动拆装箱

int i = 0;
Long j = i;

int类型的包装类是Integer,无法转化成Long类型。


关注点4:MySQL int的取值范围(先记在这,哈哈)

记得有这样一道面试题:如果采用自增int作为主键,主键不够用怎么办。很多小伙伴可能会答换成更大的类型long。无符号int类型作为主键,有着很大的取值范围,如果表的记录无需到达int取值上限,就需要考虑分表了。

二、浮点类型

关注点1:原码、反码、补码、移码

对于正数,原码、反码、补码相同,均为正数本身。
对于负数:原码的符号位是1。反码符号位为1,其他位为原码取反。补码为反码末尾加1。

原码的出现是为了引入负数。

原码:1111 1111 ~ 0111 1111
真值范围:-127 ~127255个)
其中1000 00000000 0000都表示0

原码存在带符号位运算的问题。

-1:1000 0001(原码)
+1:0000 0001(原码)
加和:1000 0010(原码) = -2是不正确的

反码的定义:如果是正数则保持不变,如果是负数,则除符号位之外按位取反。

-1:1111 1110(反码)
+1:0000 0001(反码)
加和:1111 1111(反码) = 1000 0000(原码) = -0 = 0

补码的出现用于解决+0和-0的问题。补码的定义就是正数和 0 的补码不变,负数的补码是其对应的正数按位取反再 +1。有了补码,8进制就可以用1000 0000表示-128,此时8进制可以表示256个数。

-1:1111 1111(补码)
+1:0000 0001(补码)
加和:(1)0000 0000(补码) = 0000 0000(原码) = 0

移码是将符号位取反的补码。

PS: 对于按位与操作,非常典型的场景是用于获取当前IP网段,即IP地址与掩码255.255.255.0进行按位与运算得到高24位。


关注点2:浮点数的表示

计算机内部采用二进制表示,浮点数是对实数的近似数值表示,其采用科学计数法来表示,由符号位、指数和有效数字三部分组成。
以单精度浮点数为例,占4个字节32位,32位包含1个符号位、8个指数位和23个有效数字。有效数字位是小数点后二进制表示。

符号位:0表示正数,1表示负数。
指数位:存储指数对应的移码。将[-128, 127]平移成正数域,IEEE标准规定指数范围是[-126, 127]。指数位仅用于表示科学计数法指数大小。
尾数位:以原码表示。正数为1,尾数形式为1.xyzxyz即有效数字。\

例1:16.35

0100-0001-1000-0010-1100-1100-1101
0:表示正数
100-0001-1131-127=4,表示指数是2^4=16
000-0010-1100-1100-1101:尾数0.35

例2:0.35

0011-1110-1011-0011-0011-0011-0011
0:表示正数
011-1110-1127-127=1,表示20次方
011-0011-0011-0011-0011:尾数位

同样是0.35,为何尾数位不同?

0.35(十进制) = 0.0101100110011001(二进制)
16.35(十进制)= 1.0000010110011001(二进制)

例2中尾数位是正确的,而对于例1中16.35,16的二进制为10000,转换为小数点前1的规格化是1.0000 * 2^4,占用了4个有效数字位。


关注点3:定点数表示金额

如上分析,使用浮点数是不一定能表示正确的数值,正如1-0.9结果不是0.1。在实际开发过程中,对精度要求高的运算过程都是采用定点数表示,并且是使用BigDecimalString参数构造器!!

public class BigDecimalTest {
    @Test
    public void test1(){
        System.out.println(0.05 + 0.01);
    }
    @Test
    public void test2(){
        BigDecimal b1 = new BigDecimal(0.05);
        BigDecimal b2 = new BigDecimal(0.01);
        System.out.println(b1.add(b2));
    }
    @Test
    public void test3(){
        BigDecimal b1 = new BigDecimal("0.05");
        BigDecimal b2 = new BigDecimal("0.01");
        System.out.println(b1.add(b2));
    }
}
运行结果:
0.060000000000000005
0.06000000000000000298372437868010820238851010799407958984375
0.06

三、随机数与类型转换

关注点1:生成随机数的方法

返回[0, 10)中的随机整数
1. (int)(Math.random() * 10)
2. 利用Random工具类
Random rand = new Random();
rand.nextInt(10);

因此,四舍五入等于当前数值加上0.5,再向下取整。方法适用于正负数。

关注点2:类型提升

(1)将比较小的类型(char/byte/short)传递给Integer.toBinaryString()方法,则该类型会自动转换为int。
(2)基本数据类型执行算数计算或按位运算时,只要类型比int小(char、byte、short类型),运算之前会总动转为int类型,得到的结果也是int类型。如果往回赋值,截断。例如,short类型-1在无符号右移10位,值仍为-1。
案例1:按位运算

short s = -1;
s = s >>> 10;
过程:
1. 原二进制表示: 
1111 1111 1111 1111
2. 先转换为32int类型
1111 1111 1111 1111 1111 1111 1111 1111
3. 进行移位操作
0000 0000 0011 1111 1111 1111 1111 1111
4. 赋值给s,截断
1111 1111 1111 1111

案例2:算数运算

short x = 1;
short y = 2;
x = (short)(x * y);
x *= y;

复合赋值不需要强制类型转换。

关注点3:除了布尔值外,其他基本数据类型可以相互转换。

发布了17 篇原创文章 · 获赞 41 · 访问量 9984

猜你喜欢

转载自blog.csdn.net/awecoder/article/details/99710358