今天无意中看了下jdk中的DataInputStream类,然后看到readLong()方法,如下:

private byte readBuffer[] = new byte[8];

public final long readLong() throws IOException {
readFully(readBuffer, 0, 8);
return (((long)readBuffer[0] << 56) +
((long)(readBuffer[1] & 255) << 48) +
((long)(readBuffer[2] & 255) << 40) +
((long)(readBuffer[3] & 255) << 32) +
((long)(readBuffer[4] & 255) << 24) +
((readBuffer[5] & 255) << 16) +
((readBuffer[6] & 255) << 8) +
((readBuffer[7] & 255) << 0));
}

顿时觉得很困惑,为什么数组里的第一个元素直接进行移位运算,而后面的都和255进行了与运算呢?

当时觉得困惑的原因是因为byte类型转成int类型应该不用做任何处理的,后来查了下资料后获得了灵感,找到了原因。

原因是这样的,在将输入流的内容读取到byte数组时,会进行截断。因为输入流读取时,虽然是按byte读取的,但是是以int类型返回,且数据范围是1~255,除非到了输入流结束时,返回才是-1。所以在将数据读取到byte数组,不可避免会进行截断,对于一般的数据可能没有问题,但是对于255这样高位以1开头的数据,会有问题。因为java都是有符号数,开头为1代表是负数。这样,在readLong()里,对数据元素进行移位时,会默认转换成int型,这样就导致byte型的255转成int型后,高位依旧为1(实际上代表的是-1了)。这样并不是我们想要的。实际上需要对这些元素进行无符号扩展,也就是高位补0。这就是为什么都要和255做与运算的原因。同样,可以考虑下为什么第一个元素没有进行与运算直接就移位了?其实答案很简单,就是因为在左移动56位后,高位的8位数字必然是数组里的第一个元素。

通过这个,我们其实可以做一些无符号左移的操作。

byte[] bytes = new byte[] { (byte) -42 };
ByteArrayInputStream input = new ByteArrayInputStream(bytes);
int i = input.read();
System.out.println("无符号数:" + i);
System.out.println("无符号二进制数:" + Integer.toBinaryString(i));

另外可以用更简单的方式:

byte b = (byte) -42;
int result = (b & 0xFF);
System.out.println("无符号数:" + result);
System.out.println("无符号二进制数:" + Integer.toBinaryString(result));

这种方式就用到上面提到的与计算方式。

DataInputStream类readLong()引起的思考的更多相关文章

  1. DataInputStream类和RandomAccessFile类的使用方法

    // DataInputStream类实现了DataInput接口,要想从文件中读入二进制数据, // 你需要将DataInputStream与某个字节源相结合,例如FileInputStream / ...

  2. 20180805-Java DataInputStream类

    DataInputStream dis = DataInputStream(InputStream in); 下面的例子演示了DataInputStream和DataOutputStream的使用,该 ...

  3. Java基础:浅谈数据输入流/数据输出流《DataInputstream类与DataOutputstream类》

     一.理论概述 数据输入/输出流(DataInputStream类与DataOutputStream类) 允许应用程序以与机器无关的方式从底层输入流中读取基本Java数据类型. 说白了就是,当读取一个 ...

  4. 关于Emit中动态类型TypeBuilder创建类标记的一点思考

      利用TypeBuilder是可以动态创建一个类型,现在有个需求,动态生成一个dll,创建类型EmployeeEx,需要继承原dll里面的Employee类,并包含Employee类上的所有类标记. ...

  5. 数据操作流DataOutputStream、DataInputStream类

    [例子1] import java.io.DataOutputStream; import java.io.File; import java.io.FileOutputStream; import ...

  6. 前端框架中 “类mixin” 模式的思考

    "类 mixin" 指的是 Vue 中的 mixin,Regular 中的 implement 使用 Mixin 的目的 首先我们需要知道为什么会有 mixin 的存在? 为了扩展 ...

  7. 关于Java构造类与对象的思考

    简单记录一下Java构造类与对象时的流程以及this和super对于特殊例子的分析. 首先,接着昨天的问题,我做出了几个变形: Pic1.原版: Pic2.去掉了T.foo方法中的this关键字: P ...

  8. c# 对 struct为什么不能继承类和结构的思考

    1.类.结构在使用的时候可以不调用构造函数,如果能够继承类,这种情况下不能够初始化基类,因为不执行构造函数 2.结构.所有的结构类型都默认是 sealed,通过 反汇编可以看到  ,这就阻止了结构被继 ...

  9. Python - 关于类(self/cls) 以及 多进程通讯的思考

    Python-多进程中关于类以及类实例的一些思考 目录 Python-多进程中关于类以及类实例的一些思考 1. 背景 2. Python 类中的函数 - staticmethod / classmet ...

随机推荐

  1. HDU 4839 The Game of Coins _(:зゝ∠)_

    The Game of Coins mark: #include"cstdio" #include"iostream" #include"queue& ...

  2. ASP.NET - TreeView控件,只操作最后一级节点

    效果: 使用母板页进行,左右页面进行跳转. 绑定TreeView控件:http://www.cnblogs.com/KTblog/p/4792302.html 主要功能: 点击节点的时候,只操作最后一 ...

  3. 慎得慌二u赫然共和任务i个屁

    http://www.huihui.cn/share/8424421 http://www.huihui.cn/share/8424375 http://www.huihui.cn/share/842 ...

  4. 正确理解Python文件读写模式字w+、a+和r+

    w+ 和 r+的差别不难理解.还有a+ +同一时候读写,就可以读又可写,边写边读.边读边写,不用flush,用seek 和 tell可測得. fp = open("a.txt", ...

  5. 一劳永逸解决UAC问题(修改QMAKE_LFLAGS_EXE的设置)

    如果你的程序跑在一个开启了UAC保护的系统中,而你的程序又没有"盾牌"的话,程序总是会受到各种阻挠的,比如读写文件,写注册表等. 有了"盾牌"的话就不会出现一些 ...

  6. JavaScript—DOM操作

  7. Indy的TCPServer到底能支持多少个连接

    最近一个项目,最开始使用IdTcpServer,在大压力测试的时候,只连接了800个多一点的客户端(每个客户端连接上之后每秒钟发送一个几十字节的报文,服务器应答).但是持续的时间不会超过10分钟,服务 ...

  8. 在安装mysql出现的错误以及解决方法

    因为手贱更新了一下驱动,结果导致无线网卡出了问题.然而就算是从官网上下载了驱动各种折腾也没有弄好,心里特别堵.无奈只有重装系统这一条路了.这里表示特别难过,因为电脑上东西实在太多了,而且各种环境变量. ...

  9. Mysql 导入导出数据结构及数据

    方式一: mysqldump -ukevin -P3306 --default-character-set=utf8 -p -h10.1.15.123 activity sign_in_user &g ...

  10. 中科燕园GIS外包----机场project地理信息系统EGIS

    对于大型机场建设project,不管project建设过程中.还是project建设完毕后.进入执行和维护阶段.必然要产生和使用到大量的各式各样的信息资料,包含project项目过程管理控制类文档,p ...