java中的数据存储,字节转换,位操作

1. java中数据存储是按照字节存储的,一个字节是8位,也就是java中的byte数据类型,java中byte表示的是有符号数,第八位(从右至左)表示的是符号位,一个字节表示的范围是2^8,也就是256个数,表示的范围是:-128到127,因为第八位始终是符号位,所以最大的正值就是0111 1111,也就是2^8 - 1, 在实际的数据存储时,是按照补码的形式存储的,为什么按照补码形式?请先了解原码,反码,补码:

首先统一按照2进制格式也就是全是0和1组成的数,简单来说:原码:就是一样的数。反码:正数:正数的反码与原码相同。负数:负数的反码,符号位为“1”,数值部分按位取反。补码:正数补码一样,负数:除符号位外,按位取反,末尾加1。

接着说为什么按照补码形式存储?

因为原码和反码表示的范围其实只有255个,冲突就在0这个地方,原码中:理论上0000 0000 与1000 0000 表示的该是同一个数,因为+0和-0相等,这样能存储的数实际上就少了一个,也就是255个。反码中:也是同样的问题:0按照2进制反码表示:0000 0000,然后神奇的发现1111 1111求出来的值同样也是0,但是是-0,在实际运算中+0和-0明明就是一个数。而补码的出现很好的解决了这个问题,也就是一个字节可以表示256个数。

按照补码的形式存储时,正数就不多说了,全部都一样只要不超出表示范围就行,负数的话,举个例子:如果存储的是aa,也就是1010 1010,那么按照计算机存储的话输出看一下:

为什么是-86,来一步一步算一下就知道了:aa == 1010 1010,取补码就是:先求反,1101 0101,再 + 1,1101 0110,再转化成10进制,注意第一位是符号位,那么就是-(2^6 + 2^4 + 2^2 + 1) = -86。计算结束。

2.知道计算机是按照补码形式存储的话,那么接下来继续看,实际的项目过程中,我们需要的可能是并不是这个值本身,怎么理解这句话呢?举个例子来说,接着上面的例子我需要的是aa,并不是计算出来的-86,怎么解决?因为java中全部按照补码的形式存储,可以把这个字节通过字节通过于运算,0xaa & 0x0ff,因为java中默认表示的数都是int类型,这样0x0ff其实就是一个4个字节的int类型的数据,这样的话计算结果就是:

居然在cmd窗口下输出还是-86,我换了下编译器,代码如下:

这样的话计算结果就对上了:2^7 + 2^6 + 2^4 + 2^2 + 2 = 170;

3.然而日在实际情况中有遇到的都没有这么easy,为了提高传输效率,对每个字节都会有所限制,举个例子来说:你传递的数只在0-255之间或者-127-128之间,那么用一个byte就可以保存一个信息,如果你传递的数在-32768-32767之间或者0-65535之间,就可以用一个short保存一个信息,以此类推int long等,如果正常传输情况也可以这样那该多好,但是真实情况并不是这样,举个例子来说:比如我需要的数的范围是0-8191或者-4095-4096的时候,这就比较麻烦了,为什么是连个范围都可以?这里说明一下,因为全部可以转化为2进制,所以这种情况就需要打破常规思维,比如我可以自己定义在传输的时候12这个数表示的实际数是8,也就是说这个数刚开始是8,在传输的时候是12,但是我解析的时候要把他再转成8,当然这其实是不符合逻辑的,我只是举了一个不恰当的例子。回到原来的问题,我需要的传输的数的范围是-4095-4096,这样的数的范围其实只需要13个二进制位就可以表示,计算一下:4096 - 4095 + 1 = 8192,这里的1代表的是0,不能把0漏掉,8192=2^13,也就是说我可以用2个字节表示一个数还绰绰有余,多出来3个字节可以表示其他的存储信息,比如这个数表示的是什么信息等等,这样的话传输效率就明显变高了,充分利用每一个字节,为了便于理解,那么就举个形象点的例子:比如传过来的数是0x3244,转化成2进制就是0011 0010 0100 0100,按照之前的假设,这样的2个字节传输过程中就可以使用后面的13个字节表示实际的数,也就是1 0010 0100 0100,表示实际的数,符号位也可以自己通过一个位来定义,假设传输的是一个有符号数,第一位表示的是符号,那么这里就是一个负数,怎么计算出他的真实值呢?

        实际情况中并不知道这是一个正数还是负数,所以先:0x3244 & 0x1000判断结果是不是等于0,

        如果等于0, 表示符号位,也就是第13位是0,那么接下来就可以0x3244 & 0x0fff转化成一个12位的无符号数的字节数据,然后 按照字节补的方式相加两个字节数据,也就是第一个字节((0x32 & 0x000f) <<8) + (0x44 & 0x00ff),这样求出来的一个数是int4个字节,因为java默认整数使用的都是int,当然如果你需要用一个short表示时也是可以的,只不过需要强制转化,注意强制转化,容易出错,计算公式如下:(short)(((0x32 & 0x000f) << 8) | (0x44 & 0x00ff)),如果是转化成short尽量使用|这个运算符。

        如果不等于0,表示符号位,也就是第13位是1,那么接下来就可以(short)(((0x32 | 0x00f0) << 8) | (0x44 & 0x00ff))这样的话得到就是一个负数,不加强转的话得到的是一个正数,因为默认的是int,4个字节,前面的16个位还是0,记得强制转化。

       当然解析就这样了,还多出来3个位,你可以存储性别,或者任何3个位都可以存储的内容了。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值