一、java中八大基本数据类型所占内存大小
从小到大的排序分别是:(记住是11224488就容易记忆了)
boolean:理论上只需要一个字符(1/8个字节),但实际按照一个字节处理。
byte:1个字节(-128~127)
char:2个字节
short: 2个字节
float:4个字节
int:4个字节
double:8个字节
long:8个字节
二、java的数据在内存中的存储形式
1、数据的二进制表示有三种:原码、反码、补码。Java中用补码形式表示数据。
2、什么是原码:
第一位正负位,1表示负,0表示正。
其余各位是二进制数表示,例如3和-3的原码如下:
3的原码00000011 -3的原码 10000011
3、什么是反码:正数是原码本身。负数原码按位取反(符号位不变)。例如3和-3的反码如下:
3的反码00000011 -3的反码11111100
4、什么是补码:正数是原码本身。负数反码加1。
3的补码是00000011 -3的补码是11111101
举一个简单的例子:
int a=-3;
byte b=-3;
内存中a b的存储是这样的:(int占4个字节,32位。byte占1个字节,8位)
a=-3没什么好说的,按照补码存储(就是反码+1):
int a = -3 11111111 11111111 11111111 11111101
b=-3,分为两步,第一步求出int -3的32位补码,然后截取后面的8位,舍弃前面的24位。因此:
byte b = -3 11111101
三、java中数据的强制转换问题
java中数据类型转换分为两种:自动类型转换和强制类型转换
1、自动类型转换:编译器会自动完成类型转换,不需要在程序中编写代码
转换规则:从存储范围小的类型到存储范围大的类型。
具体规则:byte→short(char)→int→long→float→double.
这里可能有人有疑问:前面不是说了long在内存中占8个字节(64位),float只占4个字节(32位),为什么long转换为float是从小范围转换到大范围呢?这是因为float浮点类型的数据在内存中的存储式中这样的:V=(-1)^s * M * 2^E。对于一个32位的float的数据,第1位表示符号位,即S。接下来的8位表示指数域,即E。剩下的23位,小数域,即M,M的取值范围为[1,2)或[0,1)。也就是说,浮点数在内存中的二进制值不是直接转换为十进制数值的,而是按照上述公式计算而来,通过这个公式,虽然只用到了4个字节,但是浮点数却比长整型的最大值要大。这也就是为什么在数据转换的时候,long类型转换为float类型的是从小到大范围转换的根本原因所在!
2、强制类型转换:必须在程序中编写代码。该类型转换很可能存在精度的损失。
转换规则:从存储范围大的类型到存储范围小的类型。
具体规则:double→float→long→int→short(char)→byte.
本人一般这样理解记忆,自动类型转换是很自然的类型转换,就好像人的成长过程,从小到大,自然完成,不需要任何附加手段。而强制类型转换,就好像要人返老还童,从大到小,违背自然规律,所以必须加一些强制手段,但是就算返老还童成功,也会有一定的后遗症,也就是精度损失。
这里举个简单的强制类型转换的例子:
short a = 128;
byte b = (byte) a;
short a=128为正数,在内存中以补码存储为:00000000 10000000
强制转换成byte,截取后8位,舍弃前八位,则b在内存中存储为:10000000。因为开头是1,所以为负数。即1个负数的补码是10000000。反码就是01111111(补码-1),原码是1000000(反码取反)。是128. 因为是负数,所以是-128。也就是最终结果是b=-128。
总结:弄清楚java所有类型转换的核心点就是分清楚是从小到大还是从大到小(是自然长大还是返老还童),自然长大就是符合规律,不需要外加手段就能转换,返老还童就是违背规律,需要加强制转换手段。当然这是建立在熟记每种数据类型的内存大小的基础上的。记住“11224488”口诀,并把float和double单独拎出来理解记忆就好了。