title: Java bit-shift results in negative number
body: <p>I am trying to make a method to use bit shifting to convert bytes to their hex (as a char) equivalent.  However, I am experiencing some unexpected results: some of the numbers come back as negative.  I understand that Java does not have the equivalent of unsigned integers, and I am at a loss as to how to make this work.  Here is my code:</p>
  
  <pre><code>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 &lt; bytes.length; i++) {
          System.out.println("Run: " + i);
          System.out.println("First nibble: " + hex_val[(bytes[i] &gt;&gt; 4)]);
          System.out.println("Second nibble: " + hex_val[(bytes[i] &amp; 0xf)]);
      }
  }
  </code></pre>
  
  <p>Here is the output:</p>
  
  <blockquote>
    <p>Run: 0
    First nibble: 5
    Second nibble: 8
    Run: 1
    First nibble: 6
    Second nibble: D
    Run: 2</p>
  </blockquote>
  
  <p>Followed by:  Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -8 
  at Test.main(Test.java:10)</p>
  
  <p>I know I can use String.format() to accomplish this, but I am not using that method because I need a method that works quickly while generating minimal garbage.  My question for the experts is... what can I change to make this work?</p>
  
  <p>UPDATE</p>
  
  <p>I made the changes suggested by Ted Hopp, and it worked perfectly in the test method.  I moved it over to my Android app, which converts the bytes to a MAC address into a char[] containing a formatted MAC.  I'm no longer getting negative numbers, but I am getting what appear to be random miscalculations.  Here is the method I am using:</p>
  
  <pre><code>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 &lt; 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] &gt;&gt; 4) &amp; 0x0f ];
      parser_mac[1] = parser_hex_arr[ (parser_packet_bytes[parser_skip] &amp; 0xf) ];
      parser_mac[3] = parser_hex_arr[ (parser_packet_bytes[parser_skip + 1] &gt;&gt; 4) &amp; 0x0f ];
      parser_mac[4] = parser_hex_arr[ (parser_packet_bytes[parser_skip + 1] &amp; 0xf) ];
      parser_mac[6] = parser_hex_arr[ (parser_packet_bytes[parser_skip + 2]  &gt;&gt; 4) &amp; 0x0f ];
      parser_mac[7] = parser_hex_arr[ (parser_packet_bytes[parser_skip + 2] &amp; 0xf) ];
      parser_mac[9] = parser_hex_arr[ (parser_packet_bytes[parser_skip + 3]  &gt;&gt; 4) &amp; 0x0f ];
      parser_mac[10] = parser_hex_arr[ (parser_packet_bytes[parser_skip + 3] &amp; 0xf) ];
      parser_mac[12] = parser_hex_arr[ (parser_packet_bytes[parser_skip + 4] &gt;&gt; 4) &amp; 0x0f ];
      parser_mac[13] = parser_hex_arr[ (parser_packet_bytes[parser_skip + 4] &amp; 0xf) ];
      parser_mac[15] = parser_hex_arr[ (parser_packet_bytes[parser_skip + 5] &gt;&gt; 4) &amp; 0x0f ];
      parser_mac[16] = parser_hex_arr[ (parser_packet_bytes[parser_skip + 5] &amp; 0xf) ];
  
      Log.i("PARSER", "StringBuilder.getString() = " + hex_sb.toString() + " | parser_mac = " + String.valueOf(parser_mac));
  
      formatted_mac = String.valueOf(parser_mac);
  }
  </code></pre>
  
  <p>parser_packet_bytes is a byte[] array of bytes of a packet, parser_skip is an int containing an offset where the byte is located, and hex_sb is a StringBuilder.  The output from StringBuilder.toString() should be the same as String.valueOf(parser_mac)... but it isn't.  Here is an example:  </p>
  
  <blockquote>
    <p>I/PARSER  (10860): StringBuilder.getString() = AC:22:0B:40:70:41 | parser_mac = 0B:22:0A:40:70:41</p>
    
    <p>I/PARSER  (10860): StringBuilder.getString() = C8:F7:33:0E:7E:AF | parser_mac = B8:E7:33:0D:7D:0E</p>
    
    <p>I/PARSER  (10860): StringBuilder.getString() = 58:6D:8F:BA:F5:81 | parser_mac = 58:6C:8E:A0:E5:81</p>
    
    <p>I/PARSER  (10860): StringBuilder.getString() = AC:22:0B:40:70:41 | parser_mac = 0B:22:0A:40:70:41</p>
  </blockquote>
  
  <p>My next question is... why don't they match?  Thanks for any ideas that you may have.</p>