一起Talk Android吧(第三百一十八回:Java中的类型转换)

本文介绍了一种将十六进制形式的字符串转换为十六进制形式的字节数组的方法,包括使用脚本拆分字符串及自定义码表的方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

各位看官们,大家好,上一回中咱们说的是Android中虚拟按键的例子,这一回中咱们说的例子是Java中的类型转换。闲话休提,言归正转。让我们一起Talk Android吧!

我们在本章回中介绍Java类型转换的知识,主要是把十六进制形式的字符串转换成十六进制形式的字节数组,大家听着可能不明白,我举个例子来说明:string = "aa01cf"转换成 byte[]={aa,01,cf}.注意byte数组中的aa是十六进制值,它的十进制值是170。

如何转换呢?我试过进制转换中常用的取模和取余算法,后来发现这些算法都不行,因为string中的aa无法直接转换成二进制编码,它可以转换成char,而char是ASCII编码,我需要把ASII码转换成二进制后再转换成十六进制。这样的操作太复杂了。我还试JDK中的各种方法,这些方法都无济于事,于是想到了使用脚本拆分字符串:

在每两个字符中间添加一个逗号,字符前面添加0x进行强制转换,使用拆分后的字符串手动给byte数组进行赋值。

下面是详细的代码,不过代码使用Java编写的,本来想用Python了,后来觉得Java操作字符串也很方便。转换的思路和方法都写到注释内容中了,大家可以参考:

  /* 把字符串格式的命令转换成十六进制字节的byte数组,如果命令太长,写起来很麻烦
     * 目前无法通过程序进行转换,因此使用手动的方法来转换,转换也很方便,操作如下:
     * 把字符串格式的命令传到此方法中,运行后在控制台输出信息,然后复制信息到程序中
     * 使用byte cmdData[]  = new byte[]{0xaa,0x01};来手动赋值,大括号中的内容
     * 就是手动复制来的内容,注意末尾有一个逗号不需要复制.这种转换思想使用了脚本的思维。
     */
    public String stringToHexByte(String string) {
        String cmdStr = string;
        int length = cmdStr.length()/2;
        int j =0 ;
        int i =0;

        StringBuilder sb = new StringBuilder();
        String temp = null;
        for(i=0,j=0; i<length; i++, j+=2) {
            temp = cmdStr.substring(j,j+2);
//            sb.append("(byte)0x").append(temp).append(",");
            sb.append(temp).append(" ");
        }
    }
    

后来发现这种转换对于固定的字符串有效果,对于程序中生成的字符串就不行了,因为string是在程序运行过程中生成的,而不是固定的内容。我于是想到了使用自定义码表的方式来转换,这个是受ASCII码表的启发。下面是具体的代码,转换的思路和方法都写到注释内容中了,大家可以参考:


     /* 把十六进制的字符串转换成byte数组,例如: str = "a1b2" 转换成 byes[]={a1,b2}; 
      * 转换思想:定义一个码表,其内容为0-f,每次从源字符串中取2个字符出来,第一个字符放到高字节,第二字符放到低字节 
      * 把取出的两个字符与码表做比较,如果和码表中的值相等,那么把码表的索引强制转换为byte型,虽然强制转换有损失 
      * 精度的风险,但是索引值是0-15,因此没有风险,为了降低风险还做了位的与操作。得到高低位的值后,把高位值向左 
      * 移动3位,然后与低位值进行或操作。合成后的值再做与OXFF做一次与操作,然后转换成byte类型。
      * 注意源字符串中需需要是小写字母,因为码表中没有大写字母。字符串中需要两个字符表示一个值,比如03表示一个值,0不能省略
      */
    public byte[] stringToHexBytes(String string) {
        /*//需要把字符串中的大写字母转换成小写字母,因为码表中没有大写字母 */
        String str = string.toLowerCase();
        //码表:用来和字符串中的字符做比较
        String [] codeTable = new String[]{"0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"};
        //码表的长度
        int size = codeTable.length;
        //源字符串的长度
        int length = str.length();
        //转换成byte的长度是源字符串长度的一半,因为是一个byte8位正好可以表示两个字符(0-f)
        byte[] bytes = new byte[length/2];
        byte highByte = 0x00;
        byte lowByte = 0x00;
        String subStr = null;
        int index = 0;
        for(int i=0; i<length-1; i+=2) {
            subStr = str.substring(i,i+2);
            //get HighByte
           for(int j=0; j<size; j++) {
               if(subStr.substring(0,1).equals(codeTable[j])) {
                   highByte = (byte)(j & 0X00FF);
                   break;
               }
           }

           //get LowByte
           for(int j=0; j<size; j++) {
               if(subStr.substring(1,2).equals(codeTable[j])) {
                   lowByte = (byte)(j & 0X00FF);
                   break;
               }
           }

           if(index< length/2) {
               bytes[index] = (byte) (((highByte << 4) | lowByte) & 0XFF);
               index += 1;
               highByte = lowByte = 0x00;
           }
        }

        return bytes;
    }

最后我们可以编写一个程序来做验证,下面是完整的代码:


public class ExchangeFormat {

	public static void main(String args[]) {
		String sourStr = "00ff0ff00990affa99aaaffa0990eb3a4daa9933bbb33b";
		ExchangeFormat obj = new ExchangeFormat();

		String desStr = obj.stringToHexByte(sourStr);
        byte [] bytes = obj.stringToHexBytes(sourStr);
        System.out.println("Method1: "+desStr);
        System.out.print("Method2: ");
        obj.showBytes(bytes);
	}

   /* 把字符串格式的命令转换成十六进制字节的byte数组,如果命令太长,写起来很麻烦
     * 目前无法通过程序进行转换,因此使用手动的方法来转换,转换也很方便,操作如下:
     * 把字符串格式的命令传到此方法中,运行后在控制台输出信息,然后复制信息到程序中
     * 使用byte cmdData[]  = new byte[]{0xaa,0x01};来手动赋值,大括号中的内容
     * 就是手动复制来的内容,注意末尾有一个逗号不需要复制.这种转换思想使用了脚本的思维。
     */
    public String stringToHexByte(String string) {
        String cmdStr = string;
        int length = cmdStr.length()/2;
        int j =0 ;
        int i =0;

        StringBuilder sb = new StringBuilder();
        String temp = null;
        for(i=0,j=0; i<length; i++, j+=2) {
            temp = cmdStr.substring(j,j+2);
//            sb.append("(byte)0x").append(temp).append(",");
            sb.append(temp).append(" ");
        }
    }

     /* 把十六进制的字符串转换成byte数组,例如: str = "a1b2" 转换成 byes[]={a1,b2}; 
      * 转换思想:定义一个码表,其内容为0-f,每次从源字符串中取2个字符出来,第一个字符放到高字节,第二字符放到低字节 
      * 把取出的两个字符与码表做比较,如果和码表中的值相等,那么把码表的索引强制转换为byte型,虽然强制转换有损失 
      * 精度的风险,但是索引值是0-15,因此没有风险,为了降低风险还做了位的与操作。得到高低位的值后,把高位值向左 
      * 移动3位,然后与低位值进行或操作。合成后的值再做与OXFF做一次与操作,然后转换成byte类型。
      * 注意源字符串中需需要是小写字母,因为码表中没有大写字母。
      */
    public byte[] stringToHexBytes(String string) {
        /*//需要把字符串中的大写字母转换成小写字母,因为码表中没有大写字母 */
        String str = string.toLowerCase();
        //码表:用来和字符串中的字符做比较
        String [] codeTable = new String[]{"0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"};
        //码表的长度
        int size = codeTable.length;
        //源字符串的长度
        int length = str.length();
        //转换成byte的长度是源字符串长度的一半,因为是一个byte8位正好可以表示两个字符(0-f)
        byte[] bytes = new byte[length/2];
        byte highByte = 0x00;
        byte lowByte = 0x00;
        String subStr = null;
        int index = 0;
        for(int i=0; i<length; i+=2) {
            subStr = str.substring(i,i+2);
            //get HighByte
           for(int j=0; j<size; j++) {
               if(subStr.substring(0,1).equals(codeTable[j])) {
                   highByte = (byte)(j & 0X00FF);
                   break;
               }
           }

           //get LowByte
           for(int j=0; j<size; j++) {
               if(subStr.substring(1,2).equals(codeTable[j])) {
                   lowByte = (byte)(j & 0X00FF);
                   break;
               }
           }

           if(index< length/2) {
               bytes[index] = (byte) (((highByte << 4) | lowByte) & 0XFF);
               index += 1;
               highByte = lowByte = 0x00;
           }
        }

        return bytes;
    }

    public void showBytes(Byte [] bytes) {
      StringBuilder strBuilder = new StringBuilder("[");
      String result = null;

      // for (byte item: bytes) {
      //     strBuilder.append(String.format("%x ", item));
      // }

      // strBuilder.append(" ]");
      // result = strBuilder.toString();

     //    System.out.println(result);

      //使用上面或者下面的方法都可以输出十六进制,不过下面的方法可以控制输出宽度
        System.out.print("[");
        for(byte item: bytes) {
          System.out.printf("%2x ",item);
        }
        System.out.print("]");
}

在控制台中编译并且运行程序,结果如下:

javac ExchangeFormat.java
java ExchangeFormat
Method1: [00 ff 0f f0 09 90 af fa 99 aa af fa 09 90 eb 3a 4d aa 99 33 bb b3 3b ]
Method2: [ 0 ff  f f0  9 90 af fa 99 aa af fa  9 90 eb 3a 4d aa 99 33 bb b3 3b ]

从运行结果可以看到,我们使用两种方法都可以对字符串进行转换,最重要的是转换后得到了相同的结果,有看官说部分值不一样,比如09和9不一样,实际上这个两个值在十六进制下是相等的,只是显示的时候没有显示9前面的0.

看官们,关于Java类型转换的例子咱们就介绍到这里,欲知后面还有什么例子,且听下回分解!

此外,本章回的内容我在工作遇到的问题,因此进行了总结和整理,如果大家有更加好的转换方法可以在评论区交流与讨论。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

talk_8

真诚赞赏,手有余香

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值