在做网络协议的时候,为了节省流量,通常会把一些简短的业务数据整合到一个字节中,以二进制形式用1位或几位表示。如6、7位代表valueA,而第5位到第3位代表valueB,剩下3位代表valueC。如何在Java中有效的提取出需要的数据呢?
Java中的基础数据类型和包装类型中都没有bit这个对象,因为Java中拥有位运算符,通过组合这些运算符即可实现位操作。然而位提取却不那么简单。首先Java中的byte是8位带符号整数,最高位为符号位;其次二进制在Java中是以补码表示的,对于负数的话会有空位被1填充的情况。
原理:对需要截取的位与1,则还是原值;对不需要截取的位与0,则结果为0。最后左移将空位移除,则剩余的值即为需要截取的值。
最终的位处理算法如下:
/**
* 截取字节某几位的值.
* 主要用于1个字节转换后的二进制代码每一位或几位代表一个业务含义。
* 如截取字节值为5,二进制为0000 0101,其中从第2位到第1位在一起代表一个值,截取后为10,转换整型后为2
*
* @param b 字节
* @param begin 开始位置(最高位计7)
* @param end 结束位置
*
* @return 截取后的值
*/
public static int getBitsValue(byte b,int begin,int end)
{
if(begin>7||end<0||end>begin)
throw new IllegalArgumentException();
//byte在位移时将转换为int型处理
if(b==0)
return 0;
else
{
// int and = 0;
// for(int i=begin;i>=end;i--)
// {
// and += 1 << i;
// }
int and = (2 << begin) - (1 << end); //优化后的算法,不用循环
return (b & and) >> end;
}
}
PS:其中有等比数列求和算法,原先采用循环方式,后优化算法;但实际测试性能没有差异,奇怪?!
PS2:如有更优方法请不吝赐教...
2009-03-12
1、对负数的处理有误,已修正