• 谈谈java中& 0xFF


    上篇文章写了在java中常用的操作运算符,其内容很基础,大多数开发的时候可能只会用到移位算法,而与或非操作则通常会有其他使用方式,比如我在看《How Tomcat Works》解析http请求头文件时使用了 &0xFF,其实我是有些懵b的,我不能直观的一下感受到这样的操作结果是要做什么,于是便有了上篇文章做基础,这篇文章来写 & 0xFF是怎么回事。

    在java的计算领域中,使用三种进制来存储和处理数值,分别是二进制、十进制、十六进制,其中二进制是隐式方式处理,没有哪种数据类型是使用bit二进制来直接表示的,也没有一种数据类型可以直观的记录一个二进制,所以我自己将其成为隐式的。十进制是我们日常生活用常用的数字表达形式,常用int、long 等类型表示整型,float、double表示浮点数等,接下来说说十六进制

    十六进制是平时开发不太常用的一种进制形式,使用0x为开头表示,比如Integer的最大值是使用
    public static final int   MAX_VALUE = 0x7fffffff;
    这种形式来表示,而不是MAX_VALUE = 2147483647,虽然长度看起来差不多。。。但如果熟悉了十六进制就可以直观的看出这一段表示的意思

    现在来说说进制到底是怎么处理的
    二进制:满2进1,当前位置0,比如0+1等于1不够2,则还是显示1,如果再加1得2那么应该显示为进1,就是高位加1,当前位置0,就是{1 0}=十进制2
    十进制:满10进1,当前位置0,与上面差不多,1+1是2不够10则不进位,当加到9时,再加1构成十,高位加(进)1,当前置0就变成了10,达到19的时候再加1时,高位加(进)1,当前位置0就变成了20
    十六进制:满16进1,当前位置0,同样1+1是2,不够16不进位,当达到15时再加1时是16,满16就需要进位了,高位加1,当前位置0,就是10。。。那么问题是 9+1的10 和15+1的10没法区分,然后科学家们就想了办法,用几个英文字母替代10及之后的数值,直到15,下面是十六进制与10进制对照
    十进制   : 0  1  2  3  4  5  6  7  8  9  10  11  12  13  14  15
    十六进制:0  1  2  3  4  5  6  7  8  9   A    B    C    D    E    F
    继续深入对比
          16               18                  32                100                  127            190                  255
    (1*16+0)10   (1*16+2)12  (2*16+0)20   (6*16+4)64  (7*16+15)7F  (11*16+14)BE  (15*16+15)FF
    在java 代码中,写16进制时需使用0x作为前缀,比如int i = 0xF(15)、int i=0x11(17)、
    int i=0xFF(255)。
    本篇的主角出现了,其中一个 0xFF。另一个主角是&(与运算符)。上篇有介绍&是位运算符,属于二进制的运算符, i(int)  & 0xFF,这就有意思了 i(10进制) &(二进制运算符) 0xFF(十六进制),实际到了计算层面的时候无论十进制、十六进制都会转为2进制进行计算,现在我们来看十六进制与二进制的对比
    2的n次方      2^1 ...  2^3-1    2^3        2^4-1        2^4            2^5-1          2^5           2^6-1         2^6
    十进制    :   2         7             8            15              16               31                32             63               64
    十六进制  :    2         7             8             F               10               1F                20             3F               40
    二进制   : {10}    {111}    {1000}    {1111}     {1 0000}   {1 1111}    {10 0000}  {11 1111}   {100 0000}

    2^7-1              2^7                   2^8-1                 2^8             ......     2^31-1              2^31
    127                  128                   255                      256                       2147483647      -2147483648
    7F                    80                      FF                       100                       7FFFFFFF           80000000
    {111 1111}    {1000 0000}      {1111 1111}    {1 0000 0000}   {0 后边31个1}     {1后边31个1}
    最后写的2的31次方为何为负数,是因为本段对比均以java int值作为运算范围,是有运算符号的,最大范围为32位,最左边的称为高位,是运算符号。

    0xFF可以直观的看到对应的二进制是{1111 1111},因为int类型是32位,在进行&运算时,需要补全0才可以运算,根据上篇的(与运算口诀,一 一得一,其他为0)来试一下999& 0xFF
    0000 0000  0000 0000  0000 0011  1110 0111        = 999
    &
    0000 0000  0000 0000  0000 0000  1111 1111        = 0xFF = 255
    ---------------------------------------------------------------------
    0000 0000  0000 0000  0000 0000  1110 0111        = 231

    再算一个66 & 0xFF
    0000 0000  0000 0000  0000 0000  0100 0010        = 66
    &
    0000 0000  0000 0000  0000 0000  1111 1111        = 0xFF = 255
    ---------------------------------------------------------------------
    0000 0000  0000 0000  0000 0000  0100 0010        = 66

    再来一个负数的,-1024 & 0xFF
    1111 1111  1111 1111  1111 1100  0000 0000        =-1024
    &
    0000 0000  0000 0000  0000 0000  1111 1111        = 0xFF = 255
    ---------------------------------------------------------------------
    0000 0000  0000 0000  0000 0000  00000000        = 0

    再来一个负数的,-200 & 0xFF
    1111 1111  1111 1111  1111 1111  0011 1000        =-200
    &
    0000 0000  0000 0000  0000 0000  1111 1111        = 0xFF = 255
    ---------------------------------------------------------------------
    0000 0000  0000 0000  0000 0000  0011 1000        = 56

    从以上几个例子可以看出 & 0xFF就像一把剪刀,首先把符号位变成了正符号0,然后剪掉 3个8位留最后一段8位,用行业术语叫高位、低位,使用-200举例高位低位
    1111 1111  1111 1111  1111 1111  0011 1000        =-200
    \_________高位________/   \_________低位_______/
    再啰嗦几句,最左边1位表示符号位时,从左向右是从高位向低位,这种叫做大端模式,有大端就有小端模式,深入了解大小端可去百科传送门 

    既然像一把剪刀,这把剪刀能干什么,我们来实战演练一下
    int类型数值,-3434343,然后进行向右移位操作,试试看-3434343 >> 24
      1111 1111  1100 1011  1001 1000  1001 1001   
    [{1111 1111  1111 1111  1111 1111} 1111 1111]  1100 1011  1001 1000  1001 1001 
    上篇文章我们有说,带符号右移,负数右移移动多少位就在左边补多少个1,操作后我们最后得到的值是[]内的,右边的都向右溢出舍去,我们将结果再进行 & 0xFF操作,
    1111 1111  1111 1111  1111 1111  1111 1111
    &
    0000 0000  0000 0000  0000 0000  1111 1111        = 0xFF = 255
    ---------------------------------------------------------------------
    0000 0000  0000 0000  0000 0000  1111 1111        = 255
    同样的方式我们右移16位 8位 和直接& 0xFF看到什么结果
      1111 1111  1100 1011     1001 1000  1001 1001   
    [{1111 1111  1111 1111}   1111 1111  1100 1011]  1001 1000  1001 1001(红色部分补位)
    1111 1111  1111 1111  1111 1111  1100 1011
    &
    0000 0000  0000 0000  0000 0000  1100 1011        = 0xFF = 255
    ---------------------------------------------------------------------
    0000 0000  0000 0000  0000 0000  1100 1011        = 203
    ..........以下雷同结果分别是
    0000 0000  0000 0000  0000 0000  1001 1000        = 152
    0000 0000  0000 0000  0000 0000  1001 1001        = 153
    结果组装
    int 255 = (byte) -1
    int 203 = (byte)  -53
    int 152 = (byte) -104
    int 153 = (byte) -103
    那么 -3434343 转为byte数组则是 byte [] result = { -1, -53, -104, -103 }
    容我再bb两句: -3434343和他的二进制小伙伴(还是上面灰色背景那段)
         1111 1111         1100 1011             1001 1000             1001 1001         = -3434343
    \___-1(255)____/   \_-53(203)___/    \__-104(152)___/   \___-103(153)____/
    是不是瞬间觉得nb了,这4段指的就是java中int占4byte(字节),想取出哪段的值就把他移动到最右边8位的位置,然后用 & 0xFF 剪掉前面0,留下最后8位的值,就得到想取出段的int值了(谁tm发明的,太nb了),(天空中传来小伙伴说为什么不substring ,靠!这个二进制,没提供那功能)

    在网上可以找到很多int转byte的代码,但是自己观察好他的最后byte顺序,有的是反的,我不敢保证我的顺序正确,但我敢保证我处理结果与java内置的处理结果(代码在下边)相同,伙伴自己仔细甄别

    ByteArrayOutputStream boutput = new ByteArrayOutputStream();
    DataOutputStream doutput = new DataOutputStream(boutput);
    try {
        doutput.writeInt(i);
    } catch (IOException e) {
        e.printStackTrace();
    }
    byte[] buf = boutput.toByteArray();
  • 相关阅读:
    git常用命令
    git误删文件找回方法/git版本回退方法
    如何解决inline和linline-block在浏览器中的间距问题
    windows系统如何添加ssh key到github
    如何使用git命令添加文件和提交文件
    sublime text常用快捷键
    sublime text3好用的插件
    Atom编辑器的插件
    使用SharedPreference保存用户数据的步骤
    解析xml文件步骤 -- pullparser
  • 原文地址:https://www.cnblogs.com/tiaowen/p/8306509.html
Copyright © 2020-2023  润新知