1、Java中的8种基本数据类型及其所占空间大小
数据类型 | 字节数 | 二进制位 | 范围 | 规律 |
---|---|---|---|---|
byte | 1 | 8 | -128~127 | -27~27-1 |
short | 2 | 16 | -32768~32767 | -215~215-1 |
int | 4 | 32 | -2147483648~2147483647 | -231~231-1 |
long | 8 | 64 | -9223372036854775808~-9223372036854775807 | -263~263-1 |
float | 4 | 32 | -3.403E38~3.403E38 | ±3.403E38 |
double | 8 | 64 | ||
char | 2 | 16 | ||
boolean | 1 | 8 | trur 或 false | trur 或 false |
1.1、char型(文本型)
用于存放字符的数据类型,占用2个字节,采用unicode编码,它的前128字节编码与ASCII兼容。字符的存储范围在 \u0000~ \uFFFF(0~65535),在定义字符型的数据时候要注意加' ',比如 '1'表示字符'1'而不是数值1,char c = ' 1 ';我们试着输出c看看,System.out.println(c);结果就是1,而如果我们这样输出呢System.out.println(c+0);
结果却变成了49。
1.2、浮点型
带小数的数据在Java中称为浮点型,浮点型可分为:
float类型(单精度类型),如float a = 0.1f;
double类型(双精度类型),如double b = 0.1d;(d可省略)
java浮点类型常量可以有两种表示形式:
十进制形式:314.0
科学计数法形式:3.14e2
3.14e2(科学计数法形式)= 3.14*102 = 314.0(十进制形式)
java中存储浮点数是根据IEEE,存储位数是由符号、指数和尾数组成。
浮点类型 | 长度(bit) | 符号位数(0正1负) | 指数位数(bit) | 尾数(bit) | 指数偏移 |
---|---|---|---|---|---|
float | 32 | 1 | 8 | 23 | 127 |
double | 64 | 1 | 11 | 52 | 1023 |
指数位说明:
由于float的指数位为8位,所以如果所有位为0的话,可以表示成0,如果所有位都是1的话,可以表示为255,但是指数也有正负之分,根据指数偏移127,则指数的范围现在变为-127 ~ 128(0-127 ~ 255-127)。这也就是为撒float型的数值取值范围是-2128~2128 即±3.403E38。
案例
假设我们现在存储一个浮点数6.25,先把6.25转为成二进制
最后转换为110.01,然后转换为科学计数法:1.1001 * 102,即小数点左移2位,因为所有的小数转换后开头都是1(也就是1.***),所以1为隐藏位,无需存储,最后尾数为1001,指数为2(由于指数便宜127),得到最终指数为129,因此最终6.25的存储结果为:0 10000001 10010000000000000000000
补充:在我们计算尾数的时候,如果碰到乘以2取整法最后乘不尽,那么算到最后一位就停止,剩下的不会存储,这也就是臭名昭著的浮点数精度问题,所以在使用的时候一定要注意,如果对结果有精度要求的还是要使用BigDecimal。
2、原码、反码、补码
2.1、机器数
一个数在计算机中的二进制表示形式叫做这个数的机器数。
机器数是带符号的,在计算机中用一个数的最高位存放符号,正数为0,负数为1.
比如,十进制中的数3,计算机字长为8位,转换成二进制就是00000011
,如果是-3,就是10000011
,那么这里的00000011和10000011就是机器数。
2.2、真值
因为第一位是符号位,所以机器数的形式值就不等于真正的数值。例如上面的有符号数10000011,其最高位1代表负数,其真正数值是-3,而不是形式值131.所以为区别起见,将带符号位的机器数对应的真正数值称为机器数的真值。
例: 0000 0001的真值是 +000 0001 = +1, 1000 0001的真值是 -000 0001 = -1.
下面让我们来探索一下为何机器要使用补码。
2.3、原码
原码就是符号位加上真值的绝对值,即用第一位表示符号,其余位表示值。比如如果是8位二进制:
[+1]原 = 0000 0001
[-1]原 = 1000 0001
因为第一位是符号位,所以8位二进制数的取值范围就是: 1111 1111 ~0111 1111 = -127~127
2.4、反码
反码的表示方法是:
正数的反码是其本身;
负数反码是在其原码的基础上,符号位不变,其余各位取反。
案例:
[+1] = [0000 0001]原 = [0000 0001]反
[-1] = [1000 0001]原 = [1111 1110]反
2.5、补码
补码的表示法是:
正数的补码就是其本身;
负数的补码是在其原码的基础上,符号位不变,其余各位取反,最后+1(即在反码的基础上+1).
[+1] = [0000 0001]原 = [0000 0001]反 = [0000 0001]补
[-1] = [1000 0001]原 = [1111 1110]反 = [1111 1111]补
2.6、为什么机器要使用补码
因为人脑可以知道第一位是符号位,在计算的时候我们会根据符号位,选择对真值区域的加减。但是对于计算机,加减乘除已经是最基础的运算,要设计的尽量简单。计算机辨别"符号位"显然会让计算机的基础电路设计变得十分复杂!于是人们想出了将符号位也参与运算的方法。
根据运算法则减去一个正数等于加上一个负数,即1-1 = 1+(-1) = 0,所以机器可以只有加法而没有减法,这样计算机运算的设计就简单了。
于是人们开始探索将符号位也参与运算,并且只保留加法的方法,首先来看原码:计算十进制表达式1-1=0;为了解决原码做减法的问题,出现了反码:
1-1=1+(-1)=[0000 0001]原 + [1000 0001]原 = [0000 0001]反 + [1111 1110]反 = [1111 1111]反 = [1000 0000]原 = -0
发现用反码计算减法,结果的真值部分是正确的,而唯一的问题其实就出现在"0"这个特殊的数值上,但是0带符号是没有任何意义的,而且会有[0000 0000]原 和 [1000 0000]原 两个编码表示0.
于是补码的出现,解决了0的符号以及两个编码的问题。
1-1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原 = [0000 0001]反 + [1111 1110]反 = [0000 0001]补 + [1111 1111]补 = [0000 0000]补 = [0000 0000]原
这样0用[0000 0000]表示,而以前出现问题的-0则不存在了,而且可以用[1000 0000]表示 -128。
(-1) + (-127) = [1000 0001]原 + [1111 1111]原 = [1111 1110]反 + [1000 0000]反 = [1111 1111]补 + [1000 0001]补 = [10000 0000]补
但是需要注意的是-128实际上是使用以前-0的补码来表示,所以-128并没有原码和反码表示。
3、java的位运算
3.1、与运算符&
其使用规律是:两个操作数中位都为1,结果才为1,否则结果位0。
案例:128&29
3.2、或运算符|
其使用规律如是:两个位只要有一个位为1,其结果为1,否则结果为0。
案例:128 | 129
3.3、取反/非运算符~
其运算规律是:如果位为0,其结果为1,否则结果为1。
案例:~2
案例:~-2
3.4、异或运算符^
其运算规律是:两个操作数的位中,相同结构为0,不同结果为1。
案例:15^2
3.5、移位运算符
3.5.1、左移运算符<<
其运算规则如下:
按二进制形式把所有的数字向左移动对应的位置,高位移出(舍弃,注意:符号位不变),低位的空位补0。(即当左移的运算数是int类型,没移动1位,它的第31位就要被移出并且丢弃,double和float不能进行移位运算。byte和short移位时,会自动把类型扩大位int型)。
如果移动的位数超过了该类型最大位置,那么编译器会对移动的位数取模。(如对int类型移动32位,相当于移动了0位,移动33位,相当于移动了1位)。
数学意义:在数字没有溢出的前提下,对于正数和负数,左移一位,相当于乘以2的1次方,左移n位就相当于乘以2的n次方。
案例:3<<2 (3是int类型)
3.5.2、右移运算符>>
其运算规律如下:
按二进制的形式把所有的数字向右移动对应的位数,低位移出(舍弃),高位的空位补符号位(即正数补0,负数补1)。
当右移的运算数是byte和short类型时,将自动把这些类型扩大为int型。
数学意义:右移一位相当于除以2的1次方,右移n位相当于除以2的n次方,且结果取整。
案例:11>>2(11是int类型)
3.5.3、无符号右移运算符>>>
无符号右移规则和右移规则是一样的,只是填充时不管左边的数字是正数还是负数都用0来填充,无符号右移运算只针对负数计算,因为对于正数来说这种运算没有意义。
无符号右移的规则只需要记住一点:忽略符号位扩展,0补最高位。
无符号右移只对32位和64位的值有意义。