浅谈 &0xFF操作

浅谈 &0xFF操作在java.io.FilterOutputStream.DataOutputStream:与机器无关地写入各种类型的数据以及String对象的二进制形式,从高位开始写。这样一来,任何机器上任何DataInputStream都能够读取它们。所有方法都以“write”开头,例如writeByte(),writeFloat()等。java.io.FilterOutputStream.PrintSt

大家好,又见面了,我是你们的朋友全栈君。

本文章为博主原创文章,未经授权,不得转载。

在java.io.FilterOutputStream.DataOutputStream:与机器无关地写入各种类型的数据以及String对象的二进制形式,从高位开始写。这样一来,任何机器上任何DataInputStream都能够读取它们。所有方法都以“write”开头,例如writeByte(),writeFloat()等。 

java.io.FilterOutputStream.PrintStream最初的目的是为了以可视化格式打印所有的基本数据类型以及String对象。这和DataOutputStream不同,它目的是将数据元素置入“流”中,使DataInputStream能够可移植地重构它们。

对于如何把一串字符串写成二进制,我一直迷惑不解,直到我看到下面的信息:

字符串的本质是char的序列,也就是char [ ]。因此,遍历写入每一个char,就完成了写一个字符串的功能!

那么问题又来了,如何把char写成二进制呢?

英语字母有ASCII码,可以把每个字符转换成对应的数字,那么汉字呢,日语呢,韩语呢,泰国语呢????????????????????????????????????????????????????

把心放肚子里吧,这个问题前人早就已经解决了。世界上的绝大部分字符都有一张类似于ASCII码表的字符和编码间的映射,那就是Unicode码表。看:

Unicode 字符编码标准是固定长度的字符编码方案,它包含了世界上几乎所有现用语言的字符。有关 Unicode 的信息可在最新版本的 The Unicode Standard 一书中找到,并可从 Unicode 协会 Web 站点(www.unicode.org)中找到。 Unicode 根据要编码的数据类型使用两种编码格式:8 位和 16 位。缺省编码格式是 16 位,即每个字符是 16 位(两个字节)宽,并且通常显示为 U+hhhh,其中 hhhh 是字符的十六进制代码点。虽然生成的 65000 多个代码元素足以用于 编码世界上主要语言的大多数字符,但 Unicode 标准还提供了一种扩展机制,允许编码一百多万个字符。扩展机制使用一对高位和低位代用字符来对扩展字符或补充字符进行编码。第一个(或高位)代用字符具有 U+D800 和 U+DBFF 之间的代码值,而第二个(或低位)代用字符具有 U+DC00 和 U+DFFF 之间的代码值。

unicode码真的可以用2个字节表示世界上的绝大部分字符。

至此,当看到一个char时,我仿佛看到了它背后隐隐欲现的0-65535间的数字,当看到一个String时,我仿佛看到了一串数字!

所以,DataOutputStream.writeChars(str)的源码也就明晰了

public final void writeChars(String s) throws IOException {
        int len = s.length();
      
        for (int i = 0 ; i < len ; i++) {
            int v = s.charAt(i);
            out.write((v >>> 8) & 0xFF); 
            out.write((v >>> 0) & 0xFF); 
        }
        incCount(len * 2);
    }

所以除了要遍历一遍string之外,其他的操作Yu DataOutputStream.writeShort(v)的源码没什么区别

public final void writeShort(int v) throws IOException {
        out.write((v >>> 8) & 0xFF);
        out.write((v >>> 0) & 0xFF);
        incCount(2);
    }

至此,就把一串字符串写成二进制了。

但是,你有没有一个疑问????????为什么(v >>> 8) & 0xFF ??为什么(v >>> 0) & 0xFF????不知道你有没有,反正我有。

具体疑问:1 为什么要用无符号的右移? 2 &0xFF不会使数的大小改变,为什么还要 &0xFF?

先科普一下:

0(零)xFF是16进制的255,也就是二进制的 1111,1111

& AND 按位与操作,同时为1时才是1,否则为0.

————位移运算计算机中存的都是数的补码,所以位移运算都是对补码而言的————

<< 左移 右补0

>> 有符号右移 左补符号位,即:如果符号位是1 就左补1,如果符号位是0 就左补0

>>>无符号右移 ,顾名思义,统一左补0

————————————————————————————————————————

要想知道为什么?我们应该想想,我们的目的是干什么的?开始已经讲了:先取高8位写入,再写入低8位.。

0000,0000,0000,0011     3的二进制原码,假设要写入的short字符对应的unicode码是3。

0000,0000,0000,0000      这是”>>>8″的结果                        

                  1111,1111       然后再 &0XFF                                                                         

                 0000,0000       最终结果                                                                                    

   这就得到了 3的原码0000,0000,0000,0011 的高8位。

    0000,0000,0000,0011        >>>0还是源码本身不变

                       1111,1111        &0XFF                                                                       

                      0000,0011        最终结果
这就得到了 3的原码0000,0000,0000,0011 的低8位。

其实,用有符号的右移>>也一样得到高/低8位,因为右移操作不改变数本身,返回一个新值,就像String。所以 “&0xFF” 就像计算机中的一把剪刀,当‘&’操作符两边数的bit位数相同时不改变数的大小,只是专门截出一个字节的长度。同理,&0x0F呢?得到4bits

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/150768.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • kill命令杀死所有进程_linux杀死一个进程

    kill命令杀死所有进程_linux杀死一个进程1kill:根据进程号(PID)杀死进程在linux上,一般常用的杀死进程的命令是kill,但是也有缺陷,下面说1、查看指定名称的进程,如下我查看运行python程序的进程pythonaux|greppython2、根据进程号(PID)杀死进程:第二列显示的就是进程号killPID3、强制杀死进程,有些进程可能杀不死,就加个-9参数,强制让它死掉!kill-9PID5、杀死多个进程,在后面跟多个进程的PID号即可kill-9PID1PID2PID3…

    2022年9月29日
    0
  • Selenimu Chrome驱动下载地址「建议收藏」

    Selenimu Chrome驱动下载地址「建议收藏」S

    2022年6月23日
    31
  • Python 数组操作_python中数组的表示形式

    Python 数组操作_python中数组的表示形式文章目录前言 一、numpy是什么? 二、使用步骤 1.引入库 2.读入数据 总结前言在python中本身有着列表等数据结构,但是列表只是一种数据的存储容器,不具备任何计算能力。故引入数组的概念。提示:以下是本篇文章正文内容,下面案例可供参考一、numpy是什么?NumPy是一种非常常用的第三方模块,在学习数据分析及挖掘时经常能够用到他。接下来就阐述一些使用numpy进行的基本操作。二、使用步骤1.引入库代码如下(示例):i…

    2022年8月13日
    7
  • Redis分布式锁的三种实现方式_分布式锁解决方案

    Redis分布式锁的三种实现方式_分布式锁解决方案总结写在前面:RLockrLock=redissonClient.getLock(“lbhTestLock”);使用tryLock无参方法时,redisson会自动添加一个定时任务,定时刷新锁的失效时间,如果unlock时失败,则会出现该锁一直不释放的情况。而当tryLock传释放时间时,则不会添加这个定时任务。测试如下:1、tryLock无参数@Testp…

    2022年10月15日
    0
  • 类 InputStreamReader[通俗易懂]

    类 InputStreamReader[通俗易懂]InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。每次调用 InputStreamReader 中的一个 read() 方法都会导致从底层输入流读取一个或多个字节。要启用从字节到字符的有效转换,可以提前从底层流读取更多的字节,使其超过满足当前读取操作所需的字节。

    2022年9月26日
    1
  • 拉链表的实现过程[通俗易懂]

    拉链表的实现过程[通俗易懂]拉链表的优势我就不说了,具体请参考百度百科:拉链表-百度百科推荐一个比较详细的参考文章:拉链表示例主要总结一下实现过程:分析:拉链表就是用来存储变化的数据的,每一份数据都有对应的有效期,我们需要进行的操作就是将变动的数据进行新增,同时将变动对应的前一条数据的有效期进行变更。说明:一般都是今天处理昨天的数据,本文所说的当天为所处理的数据的产生的当天。在这之前需要熟悉一下需要用到的表:表1:订单表(记录原始的数据)表2:增量数据表(记录每日变更的数据)表3:历史拉链表(我们要得到的就是这张表

    2022年10月9日
    0

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号