Java位移导致负数

时间:2013-08-26 02:48:20

标签: java bit-shift

我正在尝试使用位移来将字节转换为十六进制(作为char)等效项。但是,我遇到了一些意想不到的结果:一些数字又回来了。我知道Java没有等效的无符号整数,我不知道如何使这个工作。这是我的代码:

final static char[] hex_val = "0123456789ABCDEF".toCharArray();

public static void main(String[] args) {
    byte[] bytes = {(byte) 0x58, (byte) 0x6D, (byte) 0x8F, (byte) 0xBA, (byte) 0xF5, (byte) 0x81};

    for (int i = 0; i < bytes.length; i++) {
        System.out.println("Run: " + i);
        System.out.println("First nibble: " + hex_val[(bytes[i] >> 4)]);
        System.out.println("Second nibble: " + hex_val[(bytes[i] & 0xf)]);
    }
}

这是输出:

  

运行:0   第一次蚕食:5   第二次蚕食:8   运行:1   初步蚕食:6   第二次蚕食:D   运行:2

后跟:线程“main”中的异常java.lang.ArrayIndexOutOfBoundsException:-8 在Test.main(Test.java:10)

我知道我可以使用String.format()来完成此任务,但我没有使用该方法,因为我需要一个能够在生成最少垃圾的同时快速工作的方法。我对专家的问题是......我可以改变什么来使这项工作?

更新

我做了Ted Hopp建议的更改,它在测试方法中完美运行。我将它移动到我的Android应用程序,该应用程序将字节转换为MAC地址为包含格式化MAC的char []。我不再得到负数,但我得到的似乎是随机误算。这是我正在使用的方法:

static final char[] parser_hex_arr = "01234567890ABCDEF".toCharArray();
static final char[] parser_mac = "  :  :  :  :  :  ".toCharArray();

void parseMac() { 
    hex_sb.setLength(0);
    for (hex_counter = 0; hex_counter < 6; hex_counter++) {
        hex_sb.append(String.format("%02X", parser_packet_bytes[parser_skip + hex_counter]));
        if (!(hex_counter == 5)) {
                hex_sb.append(":");
        }
    }

    parser_mac[0] = parser_hex_arr[ (parser_packet_bytes[parser_skip] >> 4) & 0x0f ];
    parser_mac[1] = parser_hex_arr[ (parser_packet_bytes[parser_skip] & 0xf) ];
    parser_mac[3] = parser_hex_arr[ (parser_packet_bytes[parser_skip + 1] >> 4) & 0x0f ];
    parser_mac[4] = parser_hex_arr[ (parser_packet_bytes[parser_skip + 1] & 0xf) ];
    parser_mac[6] = parser_hex_arr[ (parser_packet_bytes[parser_skip + 2]  >> 4) & 0x0f ];
    parser_mac[7] = parser_hex_arr[ (parser_packet_bytes[parser_skip + 2] & 0xf) ];
    parser_mac[9] = parser_hex_arr[ (parser_packet_bytes[parser_skip + 3]  >> 4) & 0x0f ];
    parser_mac[10] = parser_hex_arr[ (parser_packet_bytes[parser_skip + 3] & 0xf) ];
    parser_mac[12] = parser_hex_arr[ (parser_packet_bytes[parser_skip + 4] >> 4) & 0x0f ];
    parser_mac[13] = parser_hex_arr[ (parser_packet_bytes[parser_skip + 4] & 0xf) ];
    parser_mac[15] = parser_hex_arr[ (parser_packet_bytes[parser_skip + 5] >> 4) & 0x0f ];
    parser_mac[16] = parser_hex_arr[ (parser_packet_bytes[parser_skip + 5] & 0xf) ];

    Log.i("PARSER", "StringBuilder.getString() = " + hex_sb.toString() + " | parser_mac = " + String.valueOf(parser_mac));

    formatted_mac = String.valueOf(parser_mac);
}

parser_packet_bytes是数据包的byte []字节数组,parser_skip是一个包含字节所在位置的偏移量的int,而hex_sb是一个StringBuilder。 StringBuilder.toString()的输出应该与String.valueOf(parser_mac)相同......但事实并非如此。这是一个例子:

  

I / PARSER(10860):StringBuilder.getString()= AC:22:0B:40:70:41 | parser_mac = 0B:22:0A:40:70:41

     

I / PARSER(10860):StringBuilder.getString()= C8:F7:33:0E:7E:AF | parser_mac = B8:E7:33:0D:7D:0E

     

I / PARSER(10860):StringBuilder.getString()= 58:6D:8F:BA:F5:81 | parser_mac = 58:6C:8E:A0:E5:81

     

I / PARSER(10860):StringBuilder.getString()= AC:22:0B:40:70:41 | parser_mac = 0B:22:0A:40:70:41

我的下一个问题是......为什么他们不匹配?感谢您提出的任何想法。

2 个答案:

答案 0 :(得分:8)

这是由于签名延期。字节值在Java中签名,因此超过0x7f的任何值都被视为负值。位移操作符在执行移位之前将两个操作数转换为整数。您需要在整数提升后屏蔽底部字节。例如:

((bytes[i] & 0xff) >> 4)

((bytes[i] >> 4) & 0x0f)

而不是

(bytes[i] >> 4)

答案 1 :(得分:4)

当将字节扩展为整数时,java将进行位扩展,因此您需要屏蔽高位。

    System.out.println("First nibble: " + hex_val[(bytes[i] >> 4) & 0x0f]);
    System.out.println("Second nibble: " + hex_val[(bytes[i] & 0x0f)]);