开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第17天,点击查看活动详情
1.背景
你穿越到了2220年,得到了一份火箭研发相关的工作,现在一位硬件工程师"梅人影"给你一个字节的数据,并给出了这个字节对应的各种报警的含义,现在你需要解析这个字节,并得出都有哪些报警。这对于监察火箭实时的情况非常重要,所以你开始阅读对应表格。
1.1.字节对应的表格
| 位序 | 报警对应0/1 | 报警对应含义 |
|---|---|---|
| 0 | 1 | 高温报警 |
| 1 | 0 | 震动报警 |
| 2 | 1 | 火箭载货超重 |
| 3 | 1 | 压力过高报警 |
| 4 | 0 | 电路短路 |
| 5 | 1 | 遭遇外星人 |
| 6 | 1 | 水资源耗尽 |
| 7 | 0 | 遭遇黑洞 |
而且“梅人影”还告诉你,它的这个字节内部的位序是小端序。
2.什么是大小端
小端(little-endian)和大端(big-endian)。
-
小端指的是将数据小的一端(即数据低字节)存储在起始地址(即低地址)。
-
大端指的是将数据大的一端(即数据高字节)存储在起始地址(即低地址)。
由于
TCP/IP规定采用大端字节序来传送网络协议数据包中的多字节整数数据,故网络字节序等于大端字节序。
我们还是举个例子吧,不然永远也说不清。
假设我们用两个字节来存储十进制数 666 ,那么就会对应 0x029A 。
我们可以从高到低去计算这个16进制数进行一下验证:
我们可以从低到高去计算这个16进制数进行一下验证:
好,现在我们有一个字节数组,需要把 0x029A 存进去,应该怎么存呢?
负责打印16进制数的工程师说:“应该直接按照咱们人类书写的顺序存,简单直接,我去取的时候,读第0个、第1个,然后打印十六进制数,完美。”
负责将16进制转换成10进制的工程师说:“别别别,这个数,咱们从低往高存。这样我计算的时候,就可以很快知道当前这一位乘以16的几次方了。”
双方就这么争吵不休,就像下图这样:
于是,双方各自创建了门派,我们把低地址存储数据高字节的 02 9A 一派,称为“大端”派;把低地址存储数据高字节的 9A 02一派,称为“小端”派。
这就是大小端之争,其实这种分歧,不仅存在于字节序,也存在于位序。
3.什么是位序?
位序又叫比特序,一个字节中的8个比特位(bit)之间的顺序问题。相应的,也有大小端:
-
小端指的是将数据小的一端(即数据低比特位)存储在起始地址(即低地址)。
-
大端指的是将数据大的一端(即数据高比特位)存储在起始地址(即低地址)。
假设我们有一个比特要存储 68 , 它对应到2进制就是 0100 0100 ,当我们用数组去存储的时候,自然也会有大小端的区别:
我们从字节序、位序两个例子中发现了,它们都是以最小的单元发生整体的翻转,字节序是以字节为单位,位序是以比特位为单位。
4. 解析字节
好了,现在我们已经弄清楚什么是位序的大端和小端了,又因为位序的大小端正好是相反的,所以我们可以使用java.util.BitSet 来存储一个字节内所有的位:
public static BitSet getBitSetFromOneByte(byte oneByte) {
BitSet bitSet = new BitSet(8);
for (int i = 0; i < 8; i++) {
bitSet.set(i, (oneByte >>> i & 1) > 0);
}
return bitSet;
}
此时我们就可以对照着解析状态了,假设我们需要解析报警“遭遇外星人”,也就是对应:
| 位序 | 报警对应0/1 | 报警对应含义 |
|---|---|---|
| 5 | 1 | 遭遇外星人 |
if (bitSetFromOneByte.get(5)){
System.out.println("外星人来啦");
}
由于它返回的是true和false,所以很有利于直接判断、流程控制。
总结
今天我们学习了使用 java.util.BitSet 来进行某个字节的某一位的判断,掘友们,你们有哪些自己工作中的高招呢?欢迎在评论区和大家一起交流。