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

Posted talk_8

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一起Talk Android吧(第三百一十八回:Java中的类型转换)相关的知识,希望对你有一定的参考价值。

各位看官们,大家好,上一回中咱们说的是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类型。
      * 注意源字符串中需需要是小写字母,因为码表中没有大写字母。
      */
    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 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类型转换的例子咱们就介绍到这里,欲知后面还有什么例子,且听下回分解!

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

以上是关于一起Talk Android吧(第三百一十八回:Java中的类型转换)的主要内容,如果未能解决你的问题,请参考以下文章

一起Talk Android吧(第五百一十八回:在Android中使用MQTT通信五)

一起Talk Android吧(第三百一十九回:Android中网络通信之TCP概述)

一起Talk Android吧(第三百一十五回:Android中的ActionBar)

一起Talk Android吧(第三百一十四回:ImageView常用属性三)

一起Talk Android吧(第三百一十三回:ImageView常用属性二)

一起Talk Android吧(第三百一十二回:ImageView常用属性一)