java二进制,字节数组,字符,十六进制,BCD编码转换

java二进制,字节数组,字符,十六进制,BCD编码转换


java中byte用二进制表示占用8位,而我们知道16进制的每个字符需要用4位二进制位来表示(23 + 22 + 21 + 20 = 15),所以我们就可以把每个byte转换成两个相应的16进制字符,即把byte的高4位和低4位分别转换成相应的16进制字符H和L,并组合起来得到byte转换到16进制字符串的结果new String(H) + new String(L)。即byte用十六进制表示只占2位。

同理,相反的转换也是将两个16进制字符转换成一个byte,原理同上。

根据以上原理,我们就可以将byte[] 数组转换为16进制字符串了,当然也可以将16进制字符串转换为byte[]数组了。 


   /*
    * 把16进制字符串转换成字节数组
    * @param hex
    * @return
    */
public static byte[] hexStringToByte(String hex) {
    int len = (hex.length() / 2); //除以2是因为十六进制比如a1使用两个字符代表一个byte
    byte[] result = new byte[len];
    char[] achar = hex.toCharArray();
    for (int i = 0; i < len; i++) {
    //乘以2是因为十六进制比如a1使用两个字符代表一个byte,pos代表的是数组的位置
     //第一个16进制数的起始位置是0第二个是2以此类推 
 int pos = i * 2; 
 
     //<<4位就是乘以16  比如说十六进制的"11",在这里也就是1*16|1,而其中的"|"或运算就相当于十进制中的加法运算 
    //如00010000|00000001结果就是00010001 而00010000就有点类似于十进制中10而00000001相当于十进制中的1,与是其中的或运算就相当于是10+1(此处说法可能不太对,)
     result[i] = (byte) (toByte(achar[pos]) << 4 | toByte(achar[pos + 1]));
    }
    return result;
}
 
private static byte toByte(char c) {
    byte b = (byte) "0123456789ABCDEF".indexOf(c);
    return b;
}
 
/**
    * 把字节数组转换成16进制字符串
    * @param bArray
    * @return
    */
public static final String bytesToHexString(byte[] bArray) {
    StringBuffer sb = new StringBuffer(bArray.length);
    String sTemp;
    for (int i = 0; i < bArray.length; i++) {
     sTemp = Integer.toHexString(0xFF & bArray[i]);
     if (sTemp.length() < 2)
      sb.append(0);
     sb.append(sTemp.toUpperCase());
    }
    return sb.toString();
}
 
/**
    * 把字节数组转换为对象
    * @param bytes
    * @return
    * @throws IOException
    * @throws ClassNotFoundException
    */
public static final Object bytesToObject(byte[] bytes) throws IOException, ClassNotFoundException {
    ByteArrayInputStream in = new ByteArrayInputStream(bytes);
    ObjectInputStream oi = new ObjectInputStream(in);
    Object o = oi.readObject();
    oi.close();
    return o;
}
 
/**
    * 把可序列化对象转换成字节数组
    * @param s
    * @return
    * @throws IOException
    */
public static final byte[] objectToBytes(Serializable s) throws IOException {
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    ObjectOutputStream ot = new ObjectOutputStream(out);
    ot.writeObject(s);
    ot.flush();
    ot.close();
    return out.toByteArray();
}
 
public static final String objectToHexString(Serializable s) throws IOException{
    return bytesToHexString(objectToBytes(s));
}
 
public static final Object hexStringToObject(String hex) throws IOException, ClassNotFoundException{
    return bytesToObject(hexStringToByte(hex));
}
 
/** *//**
    * @函数功能: BCD码转为10进制串(阿拉伯数据)
    * @输入参数: BCD码
    * @输出结果: 10进制串
    */
public static String bcd2Str(byte[] bytes){
    StringBuffer temp=new StringBuffer(bytes.length*2);
 
    for(int i=0;i<bytes.length;i++){
     temp.append((byte)((bytes[i]& 0xf0)>>>4));
     temp.append((byte)(bytes[i]& 0x0f));
    }
    return temp.toString().substring(0,1).equalsIgnoreCase("0")?temp.toString().substring(1):temp.toString();
}
 
/**
    * @函数功能: 10进制串转为BCD码
    * @输入参数: 10进制串
    * @输出结果: BCD码
    */
public static byte[] str2Bcd(String asc) {
    int len = asc.length();
    int mod = len % 2;
 
    if (mod != 0) {
     asc = "0" + asc;
     len = asc.length();
    }
 
    byte abt[] = new byte[len];
    if (len >= 2) {
     len = len / 2;
    }
 
    byte bbt[] = new byte[len];
    abt = asc.getBytes();
    int j, k;
 
    for (int p = 0; p < asc.length()/2; p++) {
     if ( (abt[2 * p] >= '0') && (abt[2 * p] <= '9')) {
      j = abt[2 * p] - '0';
     } else if ( (abt[2 * p] >= 'a') && (abt[2 * p] <= 'z')) {
      j = abt[2 * p] - 'a' + 0x0a;
     } else {
      j = abt[2 * p] - 'A' + 0x0a;
     }
 
     if ( (abt[2 * p + 1] >= '0') && (abt[2 * p + 1] <= '9')) {
      k = abt[2 * p + 1] - '0';
     } else if ( (abt[2 * p + 1] >= 'a') && (abt[2 * p + 1] <= 'z')) {
      k = abt[2 * p + 1] - 'a' + 0x0a;
     }else {
      k = abt[2 * p + 1] - 'A' + 0x0a;
     }
 
     int a = (j << 4) + k;
     byte b = (byte) a;
     bbt[p] = b;
    }
    return bbt;
}
/**
    * @函数功能: BCD码转ASC码
    * @输入参数: BCD串
    * @输出结果: ASC码
    */
public static String BCD2ASC(byte[] bytes) {
    StringBuffer temp = new StringBuffer(bytes.length * 2);
 
    for (int i = 0; i < bytes.length; i++) {
     int h = ((bytes[i] & 0xf0) >>> 4);
     int l = (bytes[i] & 0x0f);   
     temp.append(BToA[h]).append( BToA[l]);
    }
    return temp.toString() ;
}
 
/**
    * MD5加密字符串,返回加密后的16进制字符串
    * @param origin
    * @return
    */
public static String MD5EncodeToHex(String origin) { 
       return bytesToHexString(MD5Encode(origin));
     }
 
/**
    * MD5加密字符串,返回加密后的字节数组
    * @param origin
    * @return
    */
public static byte[] MD5Encode(String origin){
    return MD5Encode(origin.getBytes());
}
 
/**
    * MD5加密字节数组,返回加密后的字节数组
    * @param bytes
    * @return
    */
public static byte[] MD5Encode(byte[] bytes){
    MessageDigest md=null;
    try {
     md = MessageDigest.getInstance("MD5");
     return md.digest(bytes);
    } catch (NoSuchAlgorithmException e) {
     e.printStackTrace();
     return new byte[0];
    }

}

//关于byte: signed byte 把 0x00 ~ 0xff 映射成范围 0~127和 -128~-1 两段,比较简单的办法用 (b+256)%256的办法令其值回到0~255,或者用&0xff并赋给一个int。


java中byte转换int时为何与0xff进行与运算

在剖析该问题前请看如下代码 


public static String bytes2HexString(byte[] b) {
  String ret = "";
  for (int i = 0; i < b.length; i++) {
   String hex = Integer.toHexString(b[ i ] & 0xFF);
   if (hex.length() == 1) {
    hex = '0' + hex;
   }
   ret += hex.toUpperCase();
  }
  return ret;
}


上面是将byte[]转化十六进制的字符串,注意这里b[ i ] & 0xFF将一个byte和 0xFF进行了与运算,然后使用Integer.toHexString取得了十六进制字符串,可以看出
b[ i ] & 0xFF运算后得出的仍然是个int,那么为何要和 0xFF进行与运算呢?直接 Integer.toHexString(b[ i ]);,将byte强转为int不行吗?答案是不行的.

其原因在于:
1.byte的大小为8bits而int的大小为32bits
2.java的二进制采用的是补码形式

在这里先温习下计算机基础理论

byte是一个字节保存的,有8个位,即8个0、1。
8位的第一个位是符号位,
也就是说0000 0001代表的是数字1
1000 0000代表的就是-1
所以正数最大位0111 1111,也就是数字127
负数最大为1111 1111,也就是数字-128

上面说的是二进制原码,但是在java中采用的是补码的形式,下面介绍下什么是补码

1、反码:
一个数如果是正,则它的反码与原码相同;
一个数如果是负,则符号位为1,其余各位是对原码取反;

2、补码:利用溢出,我们可以将减法变成加法
对于十进制数,从9得到5可用减法:
9-4=5 因为4+6=10,我们可以将6作为4的补数
改写为加法:
9+6=15(去掉高位1,也就是减10)得到5.

对于十六进制数,从c到5可用减法:
c-7=5 因为7+9=16 将9作为7的补数
改写为加法:
c+9=15(去掉高位1,也就是减16)得到5.

在计算机中,如果我们用1个字节表示一个数,一个字节有8位,超过8位就进1,在内存中情况为(100000000),进位1被丢弃。

⑴一个数为正,则它的原码、反码、补码相同
⑵一个数为负,刚符号位为1,其余各位是对原码取反,然后整个数加1

- 1的原码为 10000001
- 1的反码为 11111110
+ 1
- 1的补码为 11111111

0的原码为 00000000
0的反码为 11111111(正零和负零的反码相同)
+1
0的补码为 100000000(舍掉打头的1,正零和负零的补码相同)

Integer.toHexString的参数是int,如果不进行&0xff,那么当一个byte会转换成int时,由于int是32位,而byte只有8位这时会进行补位,
例如补码11111111的十进制数为-1转换为int时变为11111111111111111111111111111111好多1啊,呵呵!即0xffffffff但是这个数是不对的,这种补位就会造成误差。
和0xff相与后,高24比特就会被清0了,结果就对了。

----
Java中的一个byte,其范围是-128~127的,而Integer.toHexString的参数本来是int,如果不进行&0xff,那么当一个byte会转换成int时,对于负数,会做位扩展,举例来说,一个byte的-1(即0xff),会被转换成int的-1(即0xffffffff),那么转化出的结果就不是我们想要的了。

而0xff默认是整形,所以,一个byte跟0xff相与会先将那个byte转化成整形运算,这样,结果中的高的24个比特就总会被清0,于是结果总是我们想要的。 

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
这是一个很有趣的问题!下面是用MASM和LINK编写的汇编语言程序,实现输入一个十进制数并输出对应的二进制数、十六进制数和BCD码的过程: ```assembly .model small .stack 100h .data decimal db ? binary db 9 dup('$') hexa db 3 dup('$') bcd db 6 dup('$') newline db 0Dh, 0Ah, '$' .code main proc mov ax, @data mov ds, ax ; 读取输入的字符 call readchar ; 将十进制数转化为二进制数 mov al, decimal call convert_2 mov binary, al ; 将十进制数转化为十六进制数 mov al, decimal call convert_16 mov hexa, al ; 将十进制数转化为BCD码 mov al, decimal call convert_BCD mov bcd, al ; 输出结果 mov ah, 09h mov dx, offset binary int 21h mov dx, offset newline int 21h mov dx, offset hexa int 21h mov dx, offset newline int 21h mov dx, offset bcd int 21h mov ah, 4Ch int 21h main endp ; 子程序:读取输入的字符 readchar proc mov ah, 01h int 21h sub al, 30h ; 将ASCII码转化为十进制数 mov decimal, al ret readchar endp ; 子程序:将十进制数转化为二进制数 convert_2 proc mov bl, 2 ; 除数为2 xor bh, bh mov cl, 7 ; 循环7次,处理8位二进制数 mov si, 0 ; 存储结果的偏移地址 convert_2_loop: mov ah, 0 ; 清空高位字节 div bl ; 除法运算 add ah, 30h ; 结果转化为ASCII码 mov [binary+si], ah ; 存储结果 inc si loop convert_2_loop ret convert_2 endp ; 子程序:将十进制数转化为十六进制数 convert_16 proc mov bl, 16 ; 除数为16 xor bh, bh mov cl, 2 ; 循环2次,处理两位十六进制数 mov si, 0 ; 存储结果的偏移地址 convert_16_loop: mov ah, 0 ; 清空高位字节 div bl ; 除法运算 cmp ah, 9 ; 判断余数是否大于9 jbe convert_16_digit ; 如果余数小于等于9,直接转化为ASCII码 add ah, 07h ; 如果余数大于9,转化为字母的ASCII码 convert_16_digit: add ah, 30h ; 结果转化为ASCII码 mov [hexa+si], ah ; 存储结果 inc si loop convert_16_loop ret convert_16 endp ; 子程序:将十进制数转化为BCD码 convert_BCD proc xor ah, ah ; 清空高位字节 xor si, si ; 初始化偏移地址 convert_BCD_loop: mov al, decimal ; 将十进制数复制到al aam ; 将al中的十位和个位分别存放在ah和al中 add ah, 30h ; 十位转化为ASCII码 mov [bcd+si], ah ; 存储十位 add al, 30h ; 个位转化为ASCII码 mov [bcd+si+1], al ; 存储个位 add si, 2 ; 偏移地址增加2个字节 cmp ah, 0 ; 判断十位是否为0 jne convert_BCD_loop ret convert_BCD endp end main ``` 这个程序使用DOSbox来运行,可以输入一个十进制数,然后输出对应的二进制数、十六进制数和BCD码。希望对你有帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值