美文网首页
byte与0xff的关系

byte与0xff的关系

作者: 尼小摩 | 来源:发表于2019-03-08 21:29 被阅读35次

最近在通过Redis hmset()方式来优化数据压缩和检索效率,本文主要分享一下在优化检索效率时遇到的一个困惑点。

直接上代码:

  def toHexString(byteArray: Array[Byte]) = {
    if (byteArray == null || byteArray.length < 1) {
      throw new IllegalArgumentException("this byteArray must not be null or empty")
    }
    val hexString = new StringBuilder
    for (i <- byteArray.indices) {
     val c = byteArray(i) & 0xff
      if (c < 0x10) {
        hexString.append("0")
      }
      hexString.append(Integer.toHexString(0xff & byteArray(i)))
    }
    hexString.toString.toLowerCase
  }

byteArray 是由一段字符串经过MD5加密后,输出的byte数组。首先介绍一下这两个概念:byteArray(i) & 0xff 计算结果是int类型,0x10十进制是16。我起初难以理解为什么在接下来的循环中要将byteArray(i) & 0xff再赋值给int类型c呢?byteArray(i)是8位二进制,0xFF转化成8位二进制就是11111111,那么byteArray(i)&0xFF不还是byteArray(i)本身吗?有意思吗?

后来我写了一个demo

/**
  * @Auther: fc.w
  * @Date: 2019/3/8
  */
object AppTe {

  def main(args: Array[String]): Unit = {
    val a: Array[Byte] = Array[Byte](10)
    a(0) = -127
    println(a(0))
    val c: Int = a(0) & 0xff
    println(c)

//    val unionId = "ohmdTtyH9H_DJS3dgYAarbo1Jfg4"
//    val mdInst = MessageDigest.getInstance("MD5")
//    val md = mdInst.digest(unionId.getBytes())
//    val r = new Array[Byte](3)
//    System.arraycopy(md, 13, r, 0, 3)
//    for (i <- r.indices) {
//      println(r(i))
//      if (r(i) < 0) {
//        println(r(i) +"    "+ (r(i) & 127))
//        r(i) = (r(i) & 127).toByte
//      }
//    }
//    println(toHexString(r))

  }
}

先打印a(0) ,在打印a(0) &0xff后的值,本来我想结果应该都是 -127.
结果:
-127
129
到底是为什么呢?&0xff反而不对了。

真不懂呀,后来往补码那个方向想了想。

记得在学计算机原理的时候,了解到计算机内的存储都是利用二进制的补码进行存储的。
复习一下,原码反码补码这三个概念

计算机存储数据机制:正数存储的二进制原码 ;负数存储的是二进制的补码;补码是负数的绝对值反码加1。

  • 对于正数(00000001)原码来说,首位表示符号位,反码 补码都是本身
  • 对于负数(100000001)原码来说,反码是对原码除了符号位之外作取反运算即(111111110)
  • 补码是对反码作+1运算即(111111111)

概念就这么简单。

0xFF 是计算机十六进制的表示: 0x就是代表十六进制,A B C D E F 分别代表10 11 12 13 14 15 F就是15 一个F 代表4位二进制:可以看做 是 8 4 2 1。

0xFF的二进制表示就是:1111 1111。 高24位补0:0000 0000 0000 0000 0000 0000 1111 1111;

-12的补码与0xFF 进行与(&)操作 最后就是0000 0000 0000 0000 0000 0000 1111 0100

当将-127赋值给a(0)时候,a(0)作为一个byte类型,其计算机存储的补码是10000001(8位)。
将a(0) 作为int类型向控制台输出的时候,jvm作了一个补位的处理,因为int类型是32位所以补位后的补码就是1111111111111111111111111 10000001(32位),这个32位二进制补码表示的也是-127.

发现没有,虽然byte->int计算机背后存储的二进制补码由10000001(8位)转化成了1111111111111111111111111 10000001(32位)很显然这两个补码表示的十进制数字依然是相同的。

但是我做byte->int的转化 所有时候都只是为了保持 十进制的一致性吗?
不一定吧?好比我们拿到的文件流转成byte数组,难道我们关心的是byte数组的十进制的值是多少吗?我们关心的是其背后二进制存储的补码吧。

所以大家应该能猜到为什么byte类型的数字要&0xff再赋值给int类型,其本质原因就是想保持二进制补码的一致性。

当byte要转化为int的时候,高的24位必然会补1,这样,其二进制补码其实已经不一致了,&0xff可以将高的24位置为0,低8位保持原样。这样做的目的就是为了保证二进制数据的一致性。

当然啦,保证了二进制数据性的同时,如果二进制被当作byte和int来解读,其10进制的值必然是不同的,因为符号位位置已经发生了变化。

例2中,int c = a(0)&0xff;
a(0)&0xff=1111111111111111111111111 10000001 & 11111111=000000000000000000000000 10000001 ,这个值算一下就是129,

所以c的输出的值就是129。有人问为什么上面的式子中a(0)不是8位而是32位,因为当系统检测到byte可能会转化成int或者说byte与int类型进行运算的时候,就会将byte的内存空间高位补1(也就是按符号位补位)扩充到32位,再参与运算。上面的0xff其实是int类型的字面量值,所以可以说byte与int进行运算。

相关文章

  • byte与0xff的关系

    最近在通过Redis hmset()方式来优化数据压缩和检索效率,本文主要分享一下在优化检索效率时遇到的一个困惑点...

  • 六号线晚报0528

    天气:晴 风力:微风 为什么要 & 0xFF byte类型的数字要&0xff再赋值给int类型,其本质原因就是想保...

  • java中byte[ ]和各种数据类型的相互转换

    1. int 转 byte[ ] 说明: & 0xff (与运算):两个bit(1或0)进行与运算时,如果两者都为...

  • byte

    byte为什么要与上0xff? https://www.cnblogs.com/think-in-java/p/5...

  • byte&0XFF的基础

    前言 最近在做代码相关的优化,找到了一个二进制转十六进制的方法: 为什么byte转int需要与0XFF 0XFF ...

  • 按位与、或、异或等运算方法总结记录

    1、十六进制数转10进制数>128 的时候,为了避免出现负数,应将其进行&0xff操作。 2、byte & 0x0...

  • [Java工具] 关于byte和int的转换

    需求 单片机通过Socket发送过来类似 { 0xff,0x0c ,0x80...}的byte数组,根据协议分为u...

  • byte[]和int相关知识点

    最近在项目中遇到了不太理解的地方,这里总结一下 问题 为什么int转byte可能是个负数 &0xff的作用 byt...

  • python加上&0xff

    写python时候遇到的 0xff的二进制是11111111,因为补码的关系,这样会避免产生负数,

  • NS数据类型转换

    1,NSData 与 NSString 2,NSData 与 Byte Byte --> NSData 3,NSD...

网友评论

      本文标题:byte与0xff的关系

      本文链接:https://www.haomeiwen.com/subject/uzvdpqtx.html