专栏名称: saka
目录
相关文章推荐
51好读  ›  专栏  ›  saka

java中大小端问题研究

saka  · 掘金  ·  · 2018-04-16 13:06

正文

java中大小端问题研究

关于大小端在内存中的存储

最近在学习读取音频格式文件的时候碰到一个问题,因为音频文件中有四个字节的int型是以 little-endian 形式存储的,需要转换为java中的 big-endian 模式。int转byte[]相对简单,只需要做位移缩窄就行了,但是byte[]转int的时候涉及到负数的问题,负数在计算机内中是以补码的形式存在的,容易出现一些问题。

数据是以二进制(0,1)的形式存储在计算机中,每一个这样的数据被称为bit,bit只能是0或者1,将8个bit位定义为一个byte,这样一个byte就能表示2^8个数据。java中1个字节就是1byte,short类型占2byte,int类型占4byte,long类型占8byte,float类型占8byte,double类型占16byte。

下面主要讲一下byte和int之间的转换。

java中没有unsinged类型,也就是byte只能是有符号类型,为了表示正负号,一般使用最高位来表示正负。比如 byte i=6 ,转为二进制码为 0000 0110 ,,在内存中存储如下:

+------------------------------+
| 0 | 0 | 0 | 0 | 0 | 1 | 1| 0 |
+------------------------------+
^
|
符号位

负数的存储相对比较麻烦,是以补码的形式存储的,补码就是对原有的正数所有的位取反码然后加1;
比如 byte i=-6 ,则相当于对6取反码然后加1;

0000 0110 取反码为 1111 1001

1111 1001 加1为 11111010

则可以得到最后的结果为 11111010 ,在内存中存储如下:

+------------------------------+
| 1 | 1 | 1 | 1 | 1 | 0 | 1| 0 |
+------------------------------+
^
|
符号位

此处可以有一个简单的验证方法,即原码+补码会越位进1。

    0000 0110
+ 1111 1010
--------------
= 1 0000 0000

在内存中存储是以byte为单位的,在byte拼接的过程中就演化除了两种形式: little-endian , big-endian
little-endian 适用于机器读懂的顺序,它是前边的地址存储低位的byte,后边的地址存储在高位的地址。
安卓的jni中全部采用 little-ednain , int i=6 ,转换为2进制表示为 0000 0110 0000 0000 0000 0000 0000 0000
在内存中的表示:

+-----------------+---------------+---------------+---------------+
|0|0|0|0|0|1|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0| 0 |0|0|0|0|0|0|
+-----------------+---------------+---------------+---------------+
^
|
符号位

big-endian 适用于人类读的顺序,前边的地址存储高位的byte,后边的地址存储低位的地址。
java中int类型的存储方式是 big-endian , int i=6 ,转换为2进制表示为 0000 0000 0000 0000 0000 0000 0000 0110 ,
在内存中的表示:

+-----------------+---------------+---------------+---------------+
| 0 |0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|1|0|
+-----------------+---------------+---------------+---------------+
^
|
符号位

同样对于 int i=-6 的计算也类似于byte的计算,先取反码再加1,然后排序:

big-endian:
+-----------------+---------------+---------------+---------------+
| 1 |1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|0|1|0|
+-----------------+---------------+---------------+---------------+
^
|
符号位

little-endian:
+-----------------+---------------+---------------+---------------+
|1|1|1|1|1|0|0|1|0|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1| 1 |1|1|1|1|1|1|
+-----------------+---------------+---------------+---------------+
^
|
符号位

利用位运算来进行大小端转换

接下来讲一下如何在byte[]和int之间转换

int num=1505;
byte[] result=new byte[4];

这样的一个整数,在java内存以二进制形式表示为:

+-----------------+---------------+---------------+---------------+
|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|1|1|1|1|0|0|0|0|1|






请到「今天看啥」查看全文