java中处理无符号数字的工具类

在大型的商业系统中需要跟其他各种语言开发的子系统或者组件通信,其他的系统可能会支持无符号数字,比如c语言开发的服务系统,但java都是有符号的,往往会造成传递过来的unsigned数字被转换为负数,造成逻辑上的错误,java 6是不会支持unsigned数字了,因此需要自己去做一些转换。代码如下:

import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

/**
 * java语言数字工具类,支持把其他语言的无符号的数字转换为java语言的数字类型,并且不会改变正负号。
 * 
 * java语言的基础数据类型都是有符号,当从其他语言接收到一个无符号的数字时,java语言会使用具有相同字节数的数字类型来接收,并可能改变其符号:
 * 比如: c语言的unsigned int32 值 0xffffffff, java语言的int类型接收后会识别为负数,而这并不是业务上所期望的,因此对于这类数据
 * 需要使用字节数多的数据类型来接收,比如上面的例子需要使用long数据类型来接收,如果是 c语言的unsigned int64值需要使用java的BigInteger来接收。
 * @author greenmoon
 *
 */
public abstract class UnsignedNumberUtil {
	/**
	 * 判断一个byte类型的数字是否为负数,如果为负数需要使用更宽类型的数据类型来接收,比如short,int,long等,一般使用short接收。
	 *
	 * @param value 
	 * @return
	 */
	public static boolean needWiden(byte value){
		// 0x80 = 10000000,即2的7次方,对于byte型数字来说就是符号位,如果符号位为1,则该数字为负数
		// 0x80也就是Byte.MIN_VALUE
		return (value & 0x80) == 0x80;
	}
	/**
	 * 判断一个short类型的数字是否为负数,如果为负数需要使用更宽类型的数据类型来接收,比如int,long等,一般使用int接收。
	 *
	 * @param value 
	 * @return
	 */
	public static boolean needWiden(short value){
		// 0x80000,即2的15次方,对于int型数字来说就是符号位,如果符号位为1,则该数字为负数
		// 0x8000也就是Short.MIN_VALUE
		return (value & 0x8000) == 0x8000;
	}
	/**
	 * 判断一个int类型的数字是否为负数,如果为负数需要使用更宽类型的数据类型来接收,使用long接收。
	 *
	 * @param value 
	 * @return
	 */
	public static boolean needWiden(int value){
		// 0x80000000,即2的31次方,对于int型数字来说就是符号位,如果符号位为1,则该数字为负数
		// 0x80000000也就是Integer.MIN_VALUE
		return (value & 0x80000000) == 0x80000000;
	}
	/**
	 * 判断一个long类型的数字是否为负数,如果为负数需要BigInteger,这是因为java基础类型中字节数最多的就是long了,超过long表示范围的需要使用java库提供的
	 * BigInteger 对象类型
	 *
	 * @param value 
	 * @return
	 */
	public static boolean needWiden(long value){
		// 0x8000000000000000L,即2的63次方,对于int型数字来说就是符号位,如果符号位为1,则该数字为负数
		// 0x8000000000000000L也就是Long.MIN_VALUE
		// 注意后面那个L,如果没有这个L,java会认为这个数字为int类型
		return (value & 0x8000000000000000L) == 0x8000000000000000L;
	}
	/**
	 * byte类型转换为short类型,如果是value>0则直接返回,java语言自动支持转换,如果value<0则需要处理符号位:
	 * @param value
	 * @return
	 */
	public static short toUnsignedByteValue(byte value){
		if(!needWiden(value)){
			return value;
		}
		short wideValue = value;
		// 使用 与 运算把高为字节设置为0,符号位为0,该数字为正数
		return (short)(wideValue & 0xff);
	}
	/**
	 * short类型转换为int类型,如果是value>0则直接返回,java语言自动支持转换,如果value<0则需要处理符号位:
	 * @param value
	 * @return
	 */
	public static int toUnsignedShortValue(short value){
		if(!needWiden(value)){
			return value;
		}
		// 使用 与 运算把高为字节设置为0,符号位为0,该数字为正数
		int wideValue = value;
		return wideValue & 0xffff;
	}
	/**
	 * int类型转换为long类型,如果是value>0则直接返回,java语言自动支持转换,如果value<0则需要处理符号位:
	 * @param value
	 * @return
	 */
	public static long toUnsignedIntValue(int value){
		if(!needWiden(value)){
			return value;
		}
		long wideValue = value;
		// 使用 与 运算把高为字节设置为0,符号位为0,该数字为正数
		// 注意后面那个L,如果没有这个L,java会认为这个数字为int类型,在运算过程中他会自动把他转换为long类型,那么最终的返回的值就还是负数,这是由于字节少的数字类型转换为字节多的类型时太会
		// 自动用符号位填充高位字节,,举个例子,
		// 例子1
		// int value = 100;
		// long lv = value; 此时低4个字节填充的是100,而高4个字节是0
		// 例子3
		// int value = 0xf0000000;
		// long lv = value; 此时低4个字节是0xf0000000, 而高4个字节是1,因为0xf0000000的符号位是1
		// 至于为什么是这样,这里不再解释,考虑一下计算机内部负数是用补码表示的这一原则
		return wideValue & 0xffffffffL;
	}
	/**
	 * long类型转换为BigInteger类型,如果是value>0则直接返回,java语言自动支持转换,如果value<0则需要处理符号位:
	 * @param value
	 * @return
	 */
	public static BigInteger toUnsignedLongValue(long value){
		if(!needWiden(value)){
			return BigInteger.valueOf(value);
		}
		// long型为8个字节,已经是占用字节最多的类型了,需要使用BigInteger来表示unsigned long了
		// 原理是获取long类型的字节数组,并把该数组作为BigInteger构造参数,然后构建BigInteger,
		// BigInteger所接收的byte数字是用大尾端表示的,因此在获取long的字节数组时使用ByteBuffer这个工具,
		// 关于大尾端、小尾端,请参见ByteOrder,或者一些操作系统相关的书籍
		ByteBuffer buffer = ByteBuffer.allocate(Long.SIZE/Byte.SIZE);
		buffer.order(ByteOrder.BIG_ENDIAN);
		buffer.putLong(value);
		return new BigInteger(1,buffer.array());
	}
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值