Преобразование 'X' - Результат форматируется как шестнадцатеричное целое число в верхнем регистре
Глядя на текст вопроса, также возможно, что это то, что запрашивается:
String[] arr = {"-1", "0", "10", "20" }; for (inti=0; i < arr.length; i++) { arr[i] = String.format("%02x", Byte.parseByte(arr[i])); } System.out.println(java.util.Arrays.toString(arr)); // prints "[ff, 00, 0a, 14]"
Здесь используется несколько ответов Integer.toHexString(int); это выполнимо, но с некоторыми оговорками. Поскольку параметром является int, в byte аргумент выполняется расширяющее примитивное преобразование, которое включает расширение знака.
byteb= -1; System.out.println(Integer.toHexString(b)); // prints "ffffffff"
8-разрядный byte, который подписан в Java, расширен до 32-разрядного int. Чтобы эффективно отменить это расширение знака, можно замаскировать byte с помощью 0xFF.
byteb= -1; System.out.println(Integer.toHexString(b & 0xFF)); // prints "ff"
Еще одна проблема с использованием toHexString заключается в том, что он не заполняется нулями:
byteb=10; System.out.println(Integer.toHexString(b & 0xFF)); // prints "a"
Оба фактора в совокупности должны сделать String.format решение более предпочтительным.
Я публикую, потому что ни один из существующих ответов не объясняет, почему их подходы работают, что, я думаю, действительно важно для этой проблемы. В некоторых случаях это приводит к тому, что предлагаемое решение кажется излишне сложным и утонченным. Для иллюстрации я приведу довольно простой подход, но я приведу немного больше деталей, чтобы помочь проиллюстрировать, почему это работает.
Прежде всего, что мы пытаемся сделать? Мы хотим преобразовать значение в байтах (или массив байтов) в строку, которая представляет шестнадцатеричное значение в ASCII. Итак, шаг первый - точно выяснить, что такое байт в Java:
Тип данных byte - это 8-разрядное целое число со знаком, дополняющее двойку. Оно имеет минимальное значение -128 и максимальное значение 127 (включительно). Тип данных byte может быть полезен для экономии памяти в больших массивах, где экономия памяти действительно имеет значение. Они также могут использоваться вместо int, где их ограничения помогают прояснить ваш код; тот факт, что диапазон переменной ограничен, может служить формой документации.
Что это значит? Несколько вещей: Во-первых, и это самое главное, это означает, что мы работаем с 8 битами. Так, например, мы можем записать число 2 как 0000 0010. Однако, поскольку это дополнение two, мы записываем отрицательное значение 2 следующим образом: 1111 1110. Это также означает, что преобразование в шестнадцатеричный формат очень простое. То есть вы просто преобразуете каждый 4-битный сегмент непосредственно в шестнадцатеричный. Обратите внимание, что для понимания смысла отрицательных чисел в этой схеме вам сначала нужно понять дополнение two . Если вы еще не понимаете дополнение two, вы можете прочитать отличное объяснение здесь: http://www.cs.cornell.edu / ~tomf/notes/cps104/twoscomp.html
Преобразование дополнения Two в шестнадцатеричный в общих чертах
Как только число дополняется двумя, преобразовать его в шестнадцатеричный очень просто. В общем, преобразование из двоичного файла в шестнадцатеричный очень простое, и, как вы увидите в следующих двух примерах, вы можете перейти непосредственно от дополнения two к шестнадцатеричному.
Примеры
Пример 1: Преобразовать 2 в шестнадцатеричный.
1) Сначала преобразуйте 2 в двоичный в дополнении two:
2 (base 10) = 00000010 (base 2)
2) Теперь преобразуйте двоичный код в шестнадцатеричный:
0000 = 0x0 in hex 0010 = 0x2 in hex
therefore 2 = 00000010 = 0x02.
Пример 2: Преобразовать -2 (в дополнение к двум) в шестнадцатеричный.
1) Сначала преобразуйте -2 в двоичный файл в дополнении two:
Теперь, когда мы рассмотрели концепцию, вы обнаружите, что мы можем достичь желаемого с помощью простой маскировки и сдвига. Главное, что нужно понимать, это то, что байт, который вы пытаетесь преобразовать, уже находится в дополнении two. Вы не выполняете это преобразование самостоятельно. Я думаю, что это основная путаница в этом вопросе. Возьмем, к примеру, следующий массив байтов:
byte[] bytes = newbyte[]{-2,2};
Мы просто вручную преобразовали их в шестнадцатеричный, как указано выше, но как мы можем сделать это в Java? Вот как:
Шаг 1: Создаем StringBuffer для хранения наших вычислений.
StringBufferbuffer=newStringBuffer();
Шаг 2: Выделите биты более высокого порядка, преобразуйте их в шестнадцатеричный и добавьте их в буфер
Учитывая двоичное число 1111 1110, мы можем выделить биты более высокого порядка, сначала сдвинув их на 4, а затем обнулив остальную часть числа. Логически это просто, однако детали реализации в Java (и многих языках) создают проблему из-за расширения знака. По сути, когда вы сдвигаете значение в байтах, Java сначала преобразует ваше значение в целое число, а затем выполняет расширение знака. Итак, хотя вы ожидаете, что 1111 1110 >> 4 будет 0000 1111, на самом деле в Java он представлен как дополнение двух 0xFFFFFFFF!
Итак, возвращаясь к нашему примеру:
11111110 >> 4 (shift right 4) = 11111111111111111111111111111111 (32 bit sign-extended number in two's complement)
Функция forDigit просто сопоставляет число, которое вы передаете, с набором шестнадцатеричных чисел 0-F.
Шаг 3: Далее нам нужно изолировать биты младшего порядка. Поскольку нужные нам биты уже находятся в правильном положении, мы можем просто замаскировать их:
11111110 & 0xF = 00000000000000000000000000001110 (recall sign extension from before) therefore: 1110 = 0xE in hex.
Как и раньше, в Java мы можем сделать все это одним выстрелом:
Character.forDigit((bytes[0] & 0xF), 16);
Собрав все это вместе, мы можем сделать это как цикл for и преобразовать весь массив целиком:
Надеюсь, это объяснение прояснит ситуацию для тех из вас, кому интересно, что именно происходит во многих примерах, которые вы найдете в Интернете. Надеюсь, я не допустил каких-либо вопиющих ошибок, но предложения и исправления очень приветствуются!
Ответ 3
Самый быстрый способ, который я пока нашел для этого, следующий:
{ t = System.currentTimeMillis(); for (inti=0; i < N; i++) { finalStringBuilderhex=newStringBuilder(2 * raw.length); for (finalbyte b : raw) { hex.append(HEXES.charAt((b & 0xF0) >> 4)).append(HEXES.charAt((b & 0x0F))); } hex.toString(); } System.out.println(System.currentTimeMillis() - t); // 50 }
{ t = System.currentTimeMillis(); for (inti=0; i < N; i++) { StringBuilderhex=newStringBuilder(2 * raw.length); for (byte b : raw) { hex.append(String.format("%02X", b)); } hex.toString(); } System.out.println(System.currentTimeMillis() - t); // 2535 }
} }
Редактировать: только что нашел кое-что немного быстрее, и это удерживается на одной строке, но не совместимо с JRE 9. Используйте на свой страх и риск
Как упоминали полигенные поставщики, String.format() это правильный ответ по сравнению с Integer.toHexString() (поскольку он правильно обрабатывает отрицательные числа).