【问题标题】:How to convert int array to hex string如何将int数组转换为十六进制字符串
【发布时间】:2015-04-20 23:22:44
【问题描述】:

我想将int 数组转换为十六进制字符串。我不确定我是否正确执行此操作。

我在另一个类中创建了一个int[],并通过通过 msg.obj 获取它。我得到了一些十六进制值,但不确定它们是否正确。

int[] readBuf = (int[]) msg.obj; //int array is in another class 
StringBuffer output=new StringBuffer();
for (int a:readBuf) {
    int val1 = a & 0xff;
    output.append(Integer.toHexString(val1));
}   
dataView.setText(output);

【问题讨论】:

  • 您希望如何将您的 int 数组转换为十六进制字符串?您能否发布具有预期输出的输入示例(最好解释为什么会出现这种输出)?
  • int val1 = a & 0xff;你扔掉了每个 int 的三个字节。
  • 代码中的任何建议 ???请。
  • 您确实需要展示一些输入/输出示例。例如"这个数组:{1, 2, 4, 8, 16, 32, 64, 128, 256, ..., 0x1000_0000} 应该变成字符串 'bfafbfafbfaf'"
  • 我正在获取这个 int 数组(每秒从远程设备获取一个值)[I@42b4f660 [I@42b76a40 [I@42b7a368 等等...

标签: java android string int hex


【解决方案1】:

假设我理解你的意图,代码有两个问题:

  1. int val1 = a & 0xff; 你只取你的 int 的最后一个字节。如果要转换整个整数,请删除&0xff。

  2. 您要确保Integer.toHexString 的输出始终在前面填充零,因此它的长度始终为 8 个字符(因为 4 字节长的 int 的每个字节都需要 2 个字符)。否则数组 {1,2,3} 和数组 {291} 都会给你相同的字符串 - 123。

这是一个快速而肮脏的工作代码示例

    public static String byteToUnsignedHex(int i) {
        String hex = Integer.toHexString(i);
        while(hex.length() < 8){
            hex = "0" + hex; 
        }
        return hex;
    }

    public static String intArrToHex(int[] arr) {
        StringBuilder builder = new StringBuilder(arr.length * 8);
        for (int b : arr) {
            builder.append(byteToUnsignedHex(b));
        }
        return builder.toString();
    }

    public static void main(String[] args){
        System.out.println(intArrToHex(new int[]{1,2,3}));
        System.out.println(intArrToHex(new int[]{291}));
        System.out.println(intArrToHex(new int[]{0xFFFFFFFF}));
    }

输出:

000000010000000200000003
00000123
ffffffff

【讨论】:

  • 感谢 Malt 的快速帮助。我会尝试实施你的策略:)
【解决方案2】:

@Malt 的回答肯定突出了您的代码的问题:它不会 0 填充 int 十六进制值;并且您使用a &amp; 0xff 将 int 屏蔽为仅获取最后 8 位。您最初的问题意味着您只是在每个int 中的最后一个byte 之后,但这真的不清楚。

您说您每秒都从远程对象获得结果。在具有大型数组的慢速机器上,使用您的方法(或者更确切地说是 Malt 的更正版本)方法将长 int[] 转换为十六进制字符串可能需要大量毫秒。

更快的方法是使用位移从每个 int 中获取每个 4 位 nibble,并从静态十六进制查找数组中获取适当的十六进制字符(请注意,这会进行 base-16 编码,您会从 base-64 编码得到更短的字符串):

public class AltConverter {
    final protected static char[] encoding = "0123456789ABCDEF".toCharArray();
    public String convertToString(int[] arr) {
        char[] encodedChars = new char[arr.length * 4 * 2];
        for (int i = 0; i < arr.length; i++) {
            int v = arr[i];
            int idx = i * 4 * 2;
            for (int j = 0; j < 8; j++) {
                encodedChars[idx + j] = encoding[(v >>> ((7-j)*4)) & 0x0F];
            }
        }
        return new String(encodedChars);
    }
}

使用 caliper(微基准测试 results here)与您的原始方法进行测试表明,这大约快 11 倍 †(警告:在我的机器上)。 编辑对于任何有兴趣运行它并比较结果的人,有一个带有源代码的gist here。

即使是单个元素数组

最初的微基准测试使用Caliper,因为我当时碰巧在尝试。我已将其重写为使用JMH。这样做时,我发现 results I linked to 并在此处复制最初使用了一个数组,该数组只为每个 int 元素填充了 0。这导致 JVM 为长度 > 1 的数组优化了 AltConverter 代码,从而在 AltConverter 与 SimpleConverter 中产生了 10 到 11 倍的人为改进。 JMH 和 Caliper 对有缺陷的和已修正的基准产生了非常相似的结果。 (更新了maven eclipse的基准项目here)。

这大约快 2 到 4 倍,具体取决于数组长度(在我的机器上™)。平均运行时结果(以 ns 为单位)为:

以纳秒为单位的平均运行时间 原始方法:SimpleConverter 新方法:AltConverter | N | Alt / ns |错误/ns |简单/ns |错误/ns | 加速 | | ---------: | ---------: | ---------: | ----------: | ---------: | --------: | | 1 | 30 | 1 | 61 | 2 | 2.0x | | 100 |第852章19 | 3,724 | 99 | 4.4 倍 | | 1000 | 7,517 | 200 | 36,484 |第879章4.9 倍 | | 1000,0 | 82,641 | 1,416 | 360,670 | 5,728 | 4.4 倍 | | 1000,00 | 1,014,612 | 241,089 | 4,006,940 | 91,870 | 3.9 倍 | | 1000,000 | 9,929,510 | 174,006 | 41,077,214 | 1,181,322 | 4.1x | | 1000,000,0 | 182,698,229 | 16,571,654 | 432,730,259 | 13,310,797 | 2.4 倍 |

†免责声明:在现实世界的应用程序中依赖微基准测试作为性能指标是危险的,但 caliper 是一个很好的基准测试框架,jmh 更好。 10x 4x 的性能差异,非常小的标准偏差,以 caliper 为单位,良好的 t 检验结果足以表明即使在更复杂的应用程序中也有良好的性能提升。

【讨论】:

  • github.com/AGBrown/SO-intarrtostring 还有一个基于 maven 的 eclipse 项目,供任何有兴趣使用 caliper 比较性能的人使用。
  • 感谢您的详细回答。我试过你的方法和它的工作。
猜你喜欢
  • 2018-03-20
  • 2011-01-17
  • 1970-01-01
  • 2014-03-19
  • 2013-02-07
  • 2020-12-09
  • 2020-07-18
相关资源
最近更新 更多