1.
Bits类是default类型的并非public类型,所以Bits类仅仅只能被IO包下的类所引用
构造方法无参数 所有方法都为静态方法,所以可以直接通过类名去访问其下的所有方法
2. 源码
/**
Utility methods for packing/unpacking primitive values in/out of byte arrays
using big-endian byte ordering.
一种对字节数组高效的封装和解封手段
使用大端字节序
这里我们解释一下什么叫大端字节序?
字节序为大于一个字节大小的数据在内存中的存储顺序(你可以理解为字节为内存最小单元的大小),
一般来说一个数据的存储空间在内存中是相邻的,对于CPU读取时,需要辨别多个存储单元所存储数据的顺序,
顺序错了可能会得到完全不一样的数据。
一般读取方式为顺序读取,分为两种,大端字节序(big-endian)和小端字节序(little-endian),
其中大端模式跟正常人类的阅读模式一样 从高地址忘低地址读(从左往右)
大端模式:数据的高位存储在低地址处,低位存储在高地址处
小端模式:数据的高位储存在高地址处,低位存储在低地址处
*/
public class Bits {
/*
Methods for unpacking primitive values from byte arrays starting at
given offsets.
从给定偏移量开始从字节数组中解压缩原始值的方法
*/
static boolean getBoolean(byte[] b, int off) {
return b[off] != 0;
}
static char getChar(byte[] b, int off) {
return (char) ((b[off + 1] & 0xFF) +
(b[off] << 8));
}
static short getShort(byte[] b, int off) {
return (short) ((b[off + 1] & 0xFF) +
(b[off] << 8));
}
static int getInt(byte[] b, int off) {
return ((b[off + 3] & 0xFF) ) +
((b[off + 2] & 0xFF) << 8) +
((b[off + 1] & 0xFF) << 16) +
((b[off ] ) << 24);
}
static float getFloat(byte[] b, int off) {
return Float.intBitsToFloat(getInt(b, off));
}
static long getLong(byte[] b, int off) {
return ((b[off + 7] & 0xFFL) ) +
((b[off + 6] & 0xFFL) << 8) +
((b[off + 5] & 0xFFL) << 16) +
((b[off + 4] & 0xFFL) << 24) +
((b[off + 3] & 0xFFL) << 32) +
((b[off + 2] & 0xFFL) << 40) +
((b[off + 1] & 0xFFL) << 48) +
(((long) b[off]) << 56);
}
static double getDouble(byte[] b, int off) {
return Double.longBitsToDouble(getLong(b, off));
}
/*
Methods for packing primitive values into byte arrays starting at given
offsets.
将原始值打包到以给定偏移量开始的字节数组的方法。
*/
static void putBoolean(byte[] b, int off, boolean val) {
b[off] = (byte) (val ? 1 : 0);
}
static void putChar(byte[] b, int off, char val) {
b[off + 1] = (byte) (val );
b[off ] = (byte) (val >>> 8);
}
static void putShort(byte[] b, int off, short val) {
b[off + 1] = (byte) (val );
b[off ] = (byte) (val >>> 8);
}
static void putInt(byte[] b, int off, int val) {
b[off + 3] = (byte) (val );
b[off + 2] = (byte) (val >>> 8);
b[off + 1] = (byte) (val >>> 16);
b[off ] = (byte) (val >>> 24);
}
static void putFloat(byte[] b, int off, float val) {
putInt(b, off, Float.floatToIntBits(val));
}
static void putLong(byte[] b, int off, long val) {
b[off + 7] = (byte) (val );
b[off + 6] = (byte) (val >>> 8);
b[off + 5] = (byte) (val >>> 16);
b[off + 4] = (byte) (val >>> 24);
b[off + 3] = (byte) (val >>> 32);
b[off + 2] = (byte) (val >>> 40);
b[off + 1] = (byte) (val >>> 48);
b[off ] = (byte) (val >>> 56);
}
static void putDouble(byte[] b, int off, double val) {
putLong(b, off, Double.doubleToLongBits(val));
}
}
3.
get方法为获得字节数组中第“off”位数据的方法,数据类型即为返回值类型
(将其类型转换,字节型转化为对应类型),比如char型大小为两个字节,
则getchar方法将“off”位和“off+1”位的二进制流合成一个16位的二进制编码
(依照大端模式排序)然后char转换并返回;int是四个字节,
所以需要“off”位到“off+3”位合成一个32位的编码然后转化并返回;其余方法同理。
put方法则是将val数据插入到字节数组中“off”位,过程为get方法的逆过程,
以putchar为例:先将val转化为二进制码,然后将其拆分为两个字节放置在“off”位和“off+1”位上
(同样依照大端模式)
4. 测试
@Test
public void test01(){
System.out.println(Bits.getBoolean("abc".getBytes(), 0)); //true
byte[] bytes = "abc".getBytes();
System.out.println(bytes[0]);//97
}
@Test
public void test02(){
System.out.println(Bits.getChar("abc".getBytes(), 0)); //慢
/* return (char) ((b[off + 1] & 0xFF) +
(b[off] << 8));*/
byte[] bytes = "abc".getBytes();
// 0xFF == 255
System.out.println(bytes[0 + 1] & 0xFF); //98
System.out.println(bytes[0] << 8); //24832
}