Java的8种数据类型包含(目录)
short
int
long
float
double
byte
char
boolean
类型记录
short
整型
位数:16bit
符号位[ 0-正 or 1-负 ] + 数据位 [ 15位 ]
取值范围[(-2^15) - (2^15-1)]
int
整型
位数:32bit
符号位[ 0-正 or 1-负 ] + 数据位[ 31位 ]
取值范围[(-2^31) - (2^31-1)]
long
整型
位数:64bit
符号位[ 0-正 or 1-负 ] + 数据位[ 63位 ]
取值范围[(-2^63) - (2^63-1)]
float
浮点型
位数:32bit
符号位[ 0-正 or 1-负 ] + 指数位[ 8位 ] + 底数位[ 1 + 23位 ]
取值范围[0.000002P-126 - 1.fffffeP+127]
double
浮点型
位数:64bit
符号位[ 0-正 or 1-负 ] + 指数位[ 11位 ] + 底数位[ 1 + 52位 ]
取值范围[0.00000 00000 001P-1022 - 1.fffff fffff fffP+1023]
byte
整型
位数:8bit
符号位[ 0-正 or 1-负 ] + 数据位[ 7位 ]
取值范围[(-2^15) - (2^15-1)]
char
字符型
位数:16bit
存储Unicode编码[ 16位 ]
boolean
布尔型
位数:不确定
只用于存储 true or false
数据类型记录
整型
整型的数据类型运算是一致的,用8位二进制存储的数据为例。在计算机中,8位二进制存储的数据只能在0000 0000 - 1111 1111范围内表示,需要在二进制数的范围内存储包含正数和负数的一个区间,要实现这个需求,首先想到的是,用0开头的二进制数来表示负数区间,1开头的二进制数来表示正数,因为所受到的教育显示正数的区间会在负数的区间的右边。
这样的区间会定义正数1为 1000 0001,2为 1000 0010,那么正数间的计算为1+1 = 1000 0001 + 1000 0001 = 1 0000 0010,存取8位得到0000 0010,按照法则,其值为-2。所以,无法使用1表示正数区间,因为正数间相加的表示正数的的符号位相加会得到10(二进制),而1溢出会省去,得到负的值。
所以符号位要定义0表示正数,1表示负数。这个时候又会出现新的问题,符号位把1定义为负数,还是没有解决刚刚的问题,换过来还是没有意义。
现在要解决的问题是符号位为1的运算,1+1=10,而由于位数的关系,1会被省去,结果还是符号位为1的两个数相加会得到0开头的数。不管1表示正数还是负数,都面临着1+1=10这样的问题,要解决这个问题,要把1+1=11,省去1才会不改变原来的符号位,但是显然1+1 != 11,但是进位可以实现这样的需求,11+19=30,1和9相加得到10进位了。
所以目标是要实现符号位1+1=11,二进制的特点是要使符号位进位,需要符号位的前一位要有1才有可能,-1或1的二进制表示是1000 0001,这样-1相加或1相加是不可能使符号位的前一位至少有一位1的,那表示这样定义是不可行的,需要反着定义,要使表示符号位1的数前一位可能存在1,需要使再前一位可能存在1,这样的结果是-1或1的二进制表示为1111 1111,-1或1相加得到的结果是1111 1111 + 1111 1111=1 1111 1110,受数据位数限制,去掉第一位1,得到1111 1110,即为2或-2,这样计算没有问题。那符号位1表示正还是负呢?
符号位1定义正或是负要能够把符号位1之外的二进制数字的排序颠倒,1111 1111 表示绝对值1,1111 1110表示绝对值2,单从二进制数看的话,1111 1111是要大于1111 1110,符号位用于1表示正数的话,那么二进制数与十进制数的大小排序会颠倒(3>2>1,-1>-2>-3),所以符号位1表示负数,这样二进制数和十进制数的大小排序是一致的,且也符合二进制的运算法则。
在计算机中,把负数 1000 0001(-1)存储成1111 1111的形式的转化法则称之为补码,二进制数存储与计算机中时,二进制码有三种形式。-1,确定符号位1,1的7位二进制数 000 0001得到的1000 0001称之为原码,除符号位外按位取反得到的1111 1110称之为反码,反码加一得到1111 1111称之为补码。所以计算机会用补码的形式存储整型数据,其过程为十进制=>原码=>补码,存储和计算都会用补码。正数的补码和反码与原码相等
整型数据类型的第一位是符号位,后面的都是数据位,故其存储精度是确定的,理论上不能存储超出存储精度的数据。用0000 0000表示数字0,正数的区间为0000 0000 - 01111 1111(0111 1111 = 1000 0000-1),十进制表示为0 - (2^7-1)。负数的区间为1000 0000 - 1111 1111,十进制表示为(-2^7) - (-1)。因为0的存在,导致byte的取值范围是(-2^7) - (2^7-1)
浮点型
浮点型数据实际上就是表示包含小数部分的数据类型,了解整型存储结构的话,以32位为例,首先想到的是符号位1位,在数据位中划分整数部分和小数部分,就像把符号位划分开一样。那么问题就是怎么划分,31位可以划分为15和16,但是这样的话整数的表达区间会变得很小,32位的int整数最大值为 2147483647 (2的31次方-1)如果划分15位的话得到的最大值是32767 (2的15次方-1),如果32位只用于存储32767范围的整数,那么它的实用性会非常低。那么把整数部分划分多一些能解决这个问题,但是又会衍生出新的问题。
十进制转换二进制小数部分的运算时,算法是把小数部分一直乘以2直到为0为止,其间得到的整数部分就是二进制表示的小数部分。
以0.51为例,
0.12=0.2(取出整数部分0剩下0.2)
0.22=0.4(取出整数部分0剩下0.4)
0.42=0.8(取出整数部分0剩下0.8)
0.82=1.6(取出整数部分1剩下0.6)
0.6*2=1.2(取出整数部分1剩下0.2)
....
得到0.1的二进制部分为00011的无限循环,没错,小数除了0.5外所有其他的小数转换为二进制得到的都是无限循环。这个结果说明了,首先,这样存储的话小数部分一定无法记录真实的值,小数部分划分的位数越多越精确。
显然以整型的方式存储小数是不合适的,定义整数部分位数要多,表示的正数区间才会大,定义的小数部分位数要多,那样才会精确。那么,如果能把整数部分要多少用多少,剩下的全部给小数,那才是最合适的。
那么就要转换一种计数方式了,56=5.610^1。科学计数法,十进制中,[1,10)10^X[整数] 可以表示任何数,如果是二进制,科学计数法会有一个惊人的发现,二进制中,科学记数法的表示是[1,2)*2^X[整数],可以发现,整数部分一定为1,除了0外。也就是说,用二进制科学记数法记录小数,只需要用一位固定的1表示二进制的整数部分,剩下的所有位数都可以用于记录二进制的小数部分,实现了刚刚的猜想,整数部分按需分配,剩下的分配给小数部分。
32位float浮点型数据和64位double浮点型数据就是基于这样的思想实现的。
32位的float数据二进制存储中,分配1位符号位,8位指数位,1+23位底数位(已经分析出二进制底数部分一定会是1开头,故23位用于存储底数的小数部分,计算机存储不会存储1,但是计算过程会使用到1)
浮点型数据的指数是没有符号位的,用0000 0001到1111 1111表示(指数是不能有0的,0^0你怎么计算) 浮点数表示0的时候会特殊表示。故指数的二进制数实际区间为[1,256],同时要表示正负区间,故二进制区间需要折半表示两个区间,得到一个[-126 - 127]的区间。底数部分实际的数字是由1开头的24位二进制数。故最大值为1111 1111 1111 1111 1111 1111,十六进制表示为ffff ff,IDEA显示的方法是十六进制的1.前移一位后补0,即1.ffff fe。
指数部分使用二进制纯正数区间表示是因为便于运算。浮点型间的运算是先把指数位标齐,即把其中指数小的一个浮点型数据的指数扩大为大的浮点型数据的指数再进行底数的运算。指数使用正数区间的意义是指数标齐的时候运算过程是两个正数运算,没有符号位的影响。
DoubleDouble的指数位使用11位二进制数表示。其余相同。
浮点数的运算中由于小数部分的二进制运算是无穷的,导致小数的精度会丢失,只能存储到有效的位数,当做一些判断的时候要尽量避免使用浮点数的小数进行大小或值得判断。比如
System.out.println(0.9f==0.9);
的输出结果是false的。
字符型
Char数据类型采用的是Unicode的编码方式,16bit。
计算机的底层只能记录和使用二进制数,表示文字和字母当然也要使用二进制数表示,Unicode的作用就是为文字定下二进制编码,Char需要2字节也就是16bit的原因是由于中文的繁多,需要使用2字节记录和存储。记录字母和数字等时需要1字节,中文需要两字节。初始化时可通过单引号内直接编辑一个字符或通常使用十进制的数字来定义。
布尔型
布尔型数据底层用0和1表示true or false。但是Java在定义的时候并没有单独为boolean数据单独规定一种二进制表示,Boolean数据存储时会转换成int的形式存储,但是定义boolean数组时会转换成byte数组存储。所以不能确定Boolean型的存储,但是也不需要去探其究竟。
网友评论