Преобразование 'X'- результат форматируется как шестнадцатеричное целое, заглавные
Глядя на текст вопроса, также возможно, что это то, что запрашивается:
String[] arr ={"-1","0","10","20"};for(int i =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аргумент, который включает расширение знака.
byte b =-1;System.out.println(Integer.toHexString(b));// prints "ffffffff"
8-разрядный byte, который подписан в Java, расширен до 32-разрядного знака int. Чтобы эффективно отменить это расширение знака, можно замаскировать byteс 0xFF.
byte b =-1;System.out.println(Integer.toHexString(b &0xFF));// prints "ff"
Другая проблема с использованием toHexStringзаключается в том, что он не дополняется нулями:
byte b =10;System.out.println(Integer.toHexString(b &0xFF));// prints "a"
Оба этих фактора должны сделать String.formatрешение более предпочтительным.
@Vivek: что такое «чрезвычайно большая ценность»? Какой вход и какой выход?
полигенасмазочные материалы
Позвольте мне объяснить еще раз .. У меня есть коллекция байтовых строк в массиве. Но то, что я должен сделать, это проанализировать каждый байт отдельно. Итак, я не хочу работать со всем массивом, но с отдельной строкой байта за раз, которая является одним из компонентов этого массива. Путаница возникла из-за слова " массив». Теперь в приведенном ниже коде: «byte bv = 10; String hexString = Integer.toHexString (bv);» CAse 1 (Получено байт: 68 Вывод шестнадцатеричных данных: 44) Случай: 2 (Получен байт: Вывод шестнадцатеричных символов:: ffffffd2) ......... Почему я получаю такой неожиданный результат для некоторых значений?
Вивек
1
@Vivek: прочитайте мой ответ об использовании toHexString. Вы должны замаскировать это & 0xFF, то Integer.toHexString(-46 & 0xFF)есть "d2".
полигенасмазочные материалы
@polygenelubricants: Большое спасибо .. Кажется, наконец-то код работает нормально. Безопасно ли сейчас использовать функцию toHexString? Или могут быть некоторые лазейки с подходом?
Вивек
1
@Vivek: это «безопасно», вам просто нужно быть осторожным и каждый раз маскировать byteзначение & 0xFF. formatрешение выше , может также потребоваться маскирование в зависимости от того, что вы на самом деле , используя в качестве аргумента.
полигенасмазочные материалы
65
Я пишу, потому что ни один из существующих ответов не объясняет, почему их подходы работают, что я считаю действительно важным для этой проблемы. В некоторых случаях это приводит к тому, что предлагаемое решение кажется излишне сложным и тонким. Для иллюстрации я приведу довольно простой подход, но я предоставлю немного больше деталей , чтобы проиллюстрировать , почему это работает.
Прежде всего, что мы пытаемся сделать? Мы хотим преобразовать байтовое значение (или массив байтов) в строку, которая представляет шестнадцатеричное значение в ASCII. Итак, первый шаг - выяснить, что такое байт в Java:
Байтовый тип данных представляет собой 8-разрядное целое число со знаком в виде двоичного числа со знаком . Он имеет минимальное значение -128 и максимальное значение 127 (включительно). Байтовый тип данных может быть полезен для сохранения памяти в больших массивах, где экономия памяти действительно имеет значение. Их также можно использовать вместо int, где их пределы помогают уточнить ваш код; тот факт, что диапазон переменной ограничен, может служить формой документации.
Что это значит? Несколько вещей: во-первых, и самое главное, это означает, что мы работаем с 8-битными . Так, например, мы можем записать число 2 как 0000 0010. Однако, поскольку оно является дополнением до двух, мы пишем отрицательное число 2, например: 1111 1110. Что также означает, что преобразование в шестнадцатеричное является очень простым. То есть вы просто конвертируете каждый 4-битный сегмент прямо в гекс. Обратите внимание, что для понимания отрицательных чисел в этой схеме вам сначала нужно понять дополнение к двум. Если вы еще не понимаете дополнение к двум, вы можете прочитать отличное объяснение здесь: http://www.cs.cornell.edu/~tomf/notes/cps104/twoscomp.html
Преобразование дополнения до двух в Hex в целом
Как только число становится дополнением до двух, его очень просто преобразовать в гекс. В общем, преобразование из двоичного в шестнадцатеричное очень просто, и, как вы увидите в следующих двух примерах, вы можете перейти непосредственно от дополнения двух до шестнадцатеричного.
Примеры
Пример 1: конвертировать 2 в шестнадцатеричное.
1) Сначала преобразуйте 2 в двоичный код в дополнении до двух:
2(base 10)=00000010(base 2)
2) Теперь преобразуйте двоичный файл в гекс:
0000=0x0 in hex
0010=0x2 in hex
therefore 2=00000010=0x02.
Пример 2: конвертировать -2 (в дополнении до двух) в шестнадцатеричное.
1) Сначала преобразуйте -2 в двоичный код в дополнении до двух:
-2(base 10)=00000010(direct conversion to binary)11111101(invert bits)11111110(add 1)
therefore:-2=11111110(in two's complement)
2) Теперь преобразуйте в Hex:
1111=0xF in hex
1110=0xE in hex
therefore:-2=11111110=0xFE.
Делать это в Java
Теперь, когда мы рассмотрели эту концепцию, вы обнаружите, что мы можем достичь того, чего хотим, с помощью простой маскировки и сдвига. Главное, что нужно понять, это то, что байт, который вы пытаетесь преобразовать, уже дополняет два. Вы не делаете это преобразование самостоятельно. Я думаю, что это серьезная путаница в этом вопросе. Возьмем для примера следующий байтовый массив:
byte[] bytes =newbyte[]{-2,2};
Мы просто вручную конвертировали их в шестнадцатеричные, но как мы можем это сделать на Java? Вот как:
Шаг 1: Создайте StringBuffer для хранения наших вычислений.
StringBuffer buffer =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)
Затем мы можем выделить биты с помощью маски:
11111111111111111111111111111111&0xF=00000000000000000000000000001111
therefore:1111=0xF in hex.
В Java мы можем сделать все это одним выстрелом:
Character.forDigit((bytes[0]>>4)&0xF,16);
Функция 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 и преобразовать весь массив:
for(int i=0; i < bytes.length; i++){
buffer.append(Character.forDigit((bytes[i]>>4)&0xF,16));
buffer.append(Character.forDigit((bytes[i]&0xF),16));}
Надеюсь, это объяснение прояснит ситуацию для тех, кто интересуется, что именно происходит во многих примерах, которые вы найдете в Интернете. Надеюсь, я не допустил вопиющих ошибок, но предложения и исправления приветствуются!
лучший ответ! Симметричная реализация шестнадцатеричной строки в байт будет преобразована, а затем использовать Character.digit(), как(byte) ((Character.digit(str.charAt(0), 16) << 4) + Character.digit(str.charAt(1), 16))
ericbn
21
Самый быстрый способ, который я пока нашел, это сделать следующее:
Это ~ в 50 раз быстрее чем String.format. если вы хотите проверить это:
publicclassMyTest{privatestaticfinalString HEXES ="0123456789ABCDEF";@Testpublicvoid test_get_hex(){byte[] raw ={(byte)0xd0,(byte)0x0b,(byte)0x01,(byte)0x2a,(byte)0x63,(byte)0x78,(byte)0x01,(byte)0x2e,(byte)0xe3,(byte)0x6c,(byte)0xd2,(byte)0xb0,(byte)0x78,(byte)0x51,(byte)0x73,(byte)0x34,(byte)0xaf,(byte)0xbb,(byte)0xa0,(byte)0x9f,(byte)0xc3,(byte)0xa9,(byte)0x00,(byte)0x1e,(byte)0xd5,(byte)0x4b,(byte)0x89,(byte)0xa3,(byte)0x45,(byte)0x35,(byte)0xd6,(byte)0x10,};int N =77777;long t;{
t =System.currentTimeMillis();for(int i =0; i < N; i++){finalStringBuilder hex =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(int i =0; i < N; i++){StringBuilder hex =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. Используйте на свой страх и риск
DatatypeConverter больше не доступен в Java 9. Опасно то, что код, использующий его, будет компилироваться в Java 1.8 или более ранней (Java 9 с более ранними настройками исходного кода), но получит исключение времени выполнения в Java 9.
Стивен М - на забастовке -
Второй момент @StephenMs: использование этого с jre9 приведет к сбою с исключением ClassNotFound
Патрик Фавр
На самом деле можно просто извлечь метод исходного кода printHexBinary из src.zip из jdk, который кажется в 1 раз быстрее, чем первый метод.
Фрукты
1
Если вы работаете с массивом char для константы HEXES, а не String и charAt (), вы получаете ~ 20% больше скорости.
byte[] bytes ={9,10,11,15,16};StringBuffer result =newStringBuffer();for(byte b : bytes){
result.append(String.format("%02X ", b));
result.append(" ");// delimiter}return result.toString();
Как уже упоминалось, полигенные смазочные материалы String.format()- это правильный ответ по сравнению с Integer.toHexString()(поскольку он правильно работает с отрицательными числами).
Это будет означать расширение, например, попробуйте -1.
полигенасмазочные материалы
байт bv = 10; String hexString = Integer.toHexString (bv); Кажется, это работает лучше ... Я могу применить его индивидуально к каждому элементу массива. Другой код (Работа с массивом) возвращает слишком большое значение. Что может быть причиной этого?
Вивек
@Vivek, это потому, что в случае bvэтого возвращает один шестнадцатеричный символ . Принимая во внимание, что остальная часть кода возвращает строку шестнадцатеричных символов . Я изменил код с помощью разделителя, чтобы вы могли понять его сейчас.
0x2D9A3
@Bar: вы все еще можете использовать, Integer.toHexStringесли вы маскируете byteс, 0xFFчтобы отменить расширение знака.
полигенасмазочные материалы
Причина 1 (Получено байт: 68 Вывод в шестнадцатеричном формате: 44) Случай: 2 (Получено байтов: Вывод в шестнадцатеричном формате:: ffffffd2) Я получаю неожиданные выходные значения в случае отрицательных байтовых массивов ... Как с этим справиться?
DatatypeConverter больше не доступен в Java 9. Опасно то, что код, использующий его, будет компилироваться в Java 1.8 или более ранней (Java 9 с более ранними настройками исходного кода), но получит исключение времени выполнения в Java 9.
Стивен М - на забастовке -
Грустно, когда вы говорите, что это не в jdk9. new BigInteger(byteArray).toString(16)это путь тогда. Есть ли проблемы с этим?
prayagupd
Может быть, не проблемы с производством, но он пропустит ведущие нули (так как они бессмысленны для числа, такого как BigInteger)
Friso
Похоже, это все еще в java 9 документах , так что, кажется, можно использовать его все еще из того, что я могу сказать
Брэд Паркс
я думаю, как объяснено здесь, все еще нормально использовать для java9, но будет удалено в будущих выпусках java. вы также все еще сможете использовать его с «новым» автономным модулем jaxb начиная с версии 2.3.0 .
рысь
11
Если вам нужно шестнадцатеричное представление постоянной ширины, т.е. 0Aвместо A, чтобы вы могли однозначно восстановить байты, попробуйте format():
StringBuilder result =newStringBuilder();for(byte bb : byteArray){
result.append(String.format("%02X", bb));}return result.toString();
Класс встроенного системного класса java.math.BigInteger( java.math.BigInteger ) совместим с двоичными и шестнадцатеричными данными:
Он имеет конструктор BigInteger(signum=1, byte[])для создания большого целого числа byte[](установите его первый параметр signum= 1для правильной обработки отрицательных байтов)
Используйте BigInteger.toString(16)для преобразования большого целого числа в шестнадцатеричную строку
Для разбора шестнадцатеричного числа используйте new BigInteger("ffa74b", 16)- неправильно обрабатывает ведущий ноль
Если вы хотите иметь начальный ноль в шестнадцатеричном результате, проверьте его размер и добавьте недостающий ноль, если необходимо:
if(hex.length()%2==1)
hex ="0"+ hex;
Ноты
Используйте new BigInteger(1, bytes)вместо new BigInteger(bytes), потому что Java « разбита по дизайну », и byteтип данных не содержит байтов, но подписан крошечными целыми числами [-128 ... 127]. Если первый байт отрицательный, BigIntegerпредполагается, что вы передаете отрицательное большое целое число. Просто передайте в 1качестве первого параметра ( signum=1).
Обратное преобразование из шестнадцатеричного формата вbyte[] хитрое: иногда в произведенный вывод входит ведущий ноль, и его следует очистить так:
Если начальный байт имеет десятичное значение меньше 16, вы также получите строку с нечетным количеством шестнадцатеричных символов.
Алекс Йоргенсон
8
Если вы счастливы использовать внешнюю библиотеку, у org.apache.commons.codec.binary.Hexкласса есть encodeHexметод, который принимает byte[]и возвращает a char[]. Этот метод НАМНОГО быстрее, чем опция формата, и включает в себя детали преобразования. Также поставляется с decodeHexметодом для обратного преобразования.
Еще более простой способ - использовать встроенные функции javax.xml.bind.DatatypeConverter / parseHexBinary и printHexBinary. См. Stackoverflow.com/questions/9655181/…
Алан Томпсон
2
+1 к этой опции. Hex также имеет метод encodeHexString, который принимает byte [] и возвращает String.
Минцзян Ши
не забывайте, что javaxпространство имен не всегда доступно.
Пакет Bouncy Castle Crypto представляет собой реализацию криптографических алгоритмов на Java. Этот jar содержит провайдера JCE и облегченный API для API криптографии Bouncy Castle для JDK 1.5 до JDK 1.8.
Пакет кодеков Apache Commons содержит простой кодер и декодеры для различных форматов, таких как Base64 и Hexadecimal. В дополнение к этим широко используемым кодерам и декодерам пакет кодеков также поддерживает набор утилит фонетического кодирования.
Это код, который я нашел для запуска быстрее всего. Я запускал его на 109015 байтовых массивах длиной 32 в 23 мс. Я запускал его на виртуальной машине, так что, вероятно, он будет работать быстрее на голом металле.
publicstaticfinalchar[] HEX_DIGITS ={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};publicstaticchar[] encodeHex(finalbyte[] data ){finalint l = data.length;finalchar[] out =newchar[l<<1];for(int i=0,j=0; i<l; i++){
out[j++]= HEX_DIGITS[(0xF0& data[i])>>>4];
out[j++]= HEX_DIGITS[0x0F& data[i]];}return out;}
Не работает: BigInteger(byteArrayOf(-1, 2, 3, 4, 5)).toString(16)возвращается"-fdfcfbfb"
Martin Vysny
Это правильный результат. Вы работаете с байтами '-1', '2' ... '5'. То есть байты не имеют визуализации ( unicode.org ), если вы намерены работать с литералом '-1', '2' ... '5', вам следует работать со строковыми значениями.
Вендер
Это неправильный результат. Значение байта Java, равное -1, фактически равно 0xFF (так же, как (int) 255), поскольку байты Java подписаны, поэтому результат должен быть FF02030405. Если вы попробуете решение @Jerinaw выше, вы увидите, что оно выведет правильный вывод. Также см. Решение Светлина Накова ниже.
Мартин Высный
2
Вот простая функция для преобразования байта в шестнадцатеричный
/**
* Encodes a single nibble.
*
* @param decoded the nibble to encode.
*
* @return the encoded half octet.
*/protectedstaticint encodeHalf(finalint decoded){switch(decoded){case0x00:case0x01:case0x02:case0x03:case0x04:case0x05:case0x06:case0x07:case0x08:case0x09:return decoded +0x30;// 0x30('0') - 0x39('9')case0x0A:case0x0B:case0x0C:case0x0D:case0x0E:case0x0F:return decoded +0x57;// 0x41('a') - 0x46('f')default:thrownewIllegalArgumentException("illegal half: "+ decoded);}}/**
* Encodes a single octet into two nibbles.
*
* @param decoded the octet to encode.
* @param encoded the array to which each encoded nibbles are written.
* @param offset the offset in the array.
*/protectedstaticvoid encodeSingle(finalint decoded,finalbyte[] encoded,finalint offset){if(encoded ==null){thrownewIllegalArgumentException("null encoded");}if(encoded.length <2){// not requiredthrownewIllegalArgumentException("encoded.length("+ encoded.length +") < 2");}if(offset <0){thrownewIllegalArgumentException("offset("+ offset +") < 0");}if(offset >= encoded.length -1){thrownewIllegalArgumentException("offset("+ offset +") >= encoded.length("+ encoded.length
+") - 1");}
encoded[offset]=(byte) encodeHalf((decoded >>4)&0x0F);
encoded[offset +1]=(byte) encodeHalf(decoded &0x0F);}/**
* Decodes given sequence of octets into a sequence of nibbles.
*
* @param decoded the octets to encode
*
* @return the encoded nibbles.
*/protectedstaticbyte[] encodeMultiple(finalbyte[] decoded){if(decoded ==null){thrownewIllegalArgumentException("null decoded");}finalbyte[] encoded =newbyte[decoded.length <<1];int offset =0;for(int i =0; i < decoded.length; i++){
encodeSingle(decoded[i], encoded, offset);
offset +=2;}return encoded;}/**
* Encodes given sequence of octets into a sequence of nibbles.
*
* @param decoded the octets to encode.
*
* @return the encoded nibbles.
*/publicbyte[] encode(finalbyte[] decoded){return encodeMultiple(decoded);}
Декодирование ...
/**
* Decodes a single nibble.
*
* @param encoded the nibble to decode.
*
* @return the decoded half octet.
*/protectedstaticint decodeHalf(finalint encoded){switch(encoded){case0x30:// '0'case0x31:// '1'case0x32:// '2'case0x33:// '3'case0x34:// '4'case0x35:// '5'case0x36:// '6'case0x37:// '7'case0x38:// '8'case0x39:// '9'return encoded -0x30;case0x41:// 'A'case0x42:// 'B'case0x43:// 'C'case0x44:// 'D'case0x45:// 'E'case0x46:// 'F'return encoded -0x37;case0x61:// 'a'case0x62:// 'b'case0x63:// 'c'case0x64:// 'd'case0x65:// 'e'case0x66:// 'f'return encoded -0x57;default:thrownewIllegalArgumentException("illegal half: "+ encoded);}}/**
* Decodes two nibbles into a single octet.
*
* @param encoded the nibble array.
* @param offset the offset in the array.
*
* @return decoded octet.
*/protectedstaticint decodeSingle(finalbyte[] encoded,finalint offset){if(encoded ==null){thrownewIllegalArgumentException("null encoded");}if(encoded.length <2){// not requiredthrownewIllegalArgumentException("encoded.length("+ encoded.length +") < 2");}if(offset <0){thrownewIllegalArgumentException("offset("+ offset +") < 0");}if(offset >= encoded.length -1){thrownewIllegalArgumentException("offset("+ offset +") >= encoded.length("+ encoded.length
+") - 1");}return(decodeHalf(encoded[offset])<<4)| decodeHalf(encoded[offset +1]);}/**
* Encodes given sequence of nibbles into a sequence of octets.
*
* @param encoded the nibbles to decode.
*
* @return the encoded octets.
*/protectedstaticbyte[] decodeMultiple(finalbyte[] encoded){if(encoded ==null){thrownewIllegalArgumentException("null encoded");}if((encoded.length &0x01)==0x01){thrownewIllegalArgumentException("encoded.length("+ encoded.length +") is not even");}finalbyte[] decoded =newbyte[encoded.length >>1];int offset =0;for(int i =0; i < decoded.length; i++){
decoded[i]=(byte) decodeSingle(encoded, offset);
offset +=2;}return decoded;}/**
* Decodes given sequence of nibbles into a sequence of octets.
*
* @param encoded the nibbles to decode.
*
* @return the decoded octets.
*/publicbyte[] decode(finalbyte[] encoded){return decodeMultiple(encoded);}
Я не мог понять, что именно вы имели в виду под байтовой строкой, но вот некоторые преобразования из байтовой в строковую и наоборот, конечно, в официальных документах намного больше
Integer intValue =149;
Соответствующее значение байта:
Byte byteValue = intValue.byteValue();// this will convert the rightmost byte of the intValue to byte, because Byte is an 8 bit object and Integer is at least 16 bit, and it will give you a signed number in this case -107
получить целочисленное значение из байтовой переменной:
Integer anInt = byteValue.intValue();// This will convert the byteValue variable to a signed Integer
От байта и целого до шестнадцатеричной строки:
так я делаю:
Integer anInt =149Byte aByte = anInt.byteValue();String hexFromInt ="".format("0x%x", anInt);// This will output 0x95String hexFromByte ="".format("0x%x", aByte);// This will output 0x95
Преобразование массива байтов в шестнадцатеричную строку.
Насколько я знаю, не существует простой функции для преобразования всех элементов в одном массиве Objectв элементы другого Object, поэтому вы должны сделать это самостоятельно. Вы можете использовать следующие функции:
От байта [] к строке:
publicstaticString byteArrayToHexString(byte[] byteArray){String hexString ="";for(int i =0; i < byteArray.length; i++){String thisByte ="".format("%x", byteArray[i]);
hexString += thisByte;}return hexString;}
И из шестнадцатеричной строки в байт []:
publicstaticbyte[] hexStringToByteArray(String hexString){byte[] bytes =newbyte[hexString.length()/2];for(int i =0; i < hexString.length(); i +=2){String sub = hexString.substring(i, i +2);Integer intVal =Integer.parseInt(sub,16);
bytes[i /2]= intVal.byteValue();String hex ="".format("0x%x", bytes[i /2]);}return bytes;}
Слишком поздно, но я надеюсь, что это может помочь другим;)
Например, для байтового массива длиной 8 используйте:
String.format("%016X",newBigInteger(1,bytes))
Преимущества:
ведущие нули
нет подписи
только встроенные функции
только одна строка кода
Недостаток:
Там могут быть более эффективные способы сделать это
Пример:
byte[] bytes =newbyte[8];Random r =newRandom();System.out.println("big-endian | two's-complement");System.out.println("-----------------|-----------------");for(int i =0; i <10; i++){
r.nextBytes(bytes);System.out.print(String.format("%016X",newBigInteger(1,bytes)));System.out.print(" | ");System.out.print(String.format("%016X",newBigInteger(bytes)));System.out.println();}
Ответы:
Смотрите также
java.util.Formatter
синтаксис%[flags][width]conversion
'0'
- результат будет дополнен нулями2
'X'
- результат форматируется как шестнадцатеричное целое, заглавныеГлядя на текст вопроса, также возможно, что это то, что запрашивается:
Несколько ответов здесь использует
Integer.toHexString(int)
; это выполнимо, но с некоторыми оговорками. Так как параметр являетсяint
расширением, преобразование примитива выполняется вbyte
аргумент, который включает расширение знака.8-разрядный
byte
, который подписан в Java, расширен до 32-разрядного знакаint
. Чтобы эффективно отменить это расширение знака, можно замаскироватьbyte
с0xFF
.Другая проблема с использованием
toHexString
заключается в том, что он не дополняется нулями:Оба этих фактора должны сделать
String.format
решение более предпочтительным.Ссылки
byte
, от-128
до127
, включительноисточник
toHexString
. Вы должны замаскировать это& 0xFF
, тоInteger.toHexString(-46 & 0xFF)
есть"d2"
.byte
значение& 0xFF
.format
решение выше , может также потребоваться маскирование в зависимости от того, что вы на самом деле , используя в качестве аргумента.Я пишу, потому что ни один из существующих ответов не объясняет, почему их подходы работают, что я считаю действительно важным для этой проблемы. В некоторых случаях это приводит к тому, что предлагаемое решение кажется излишне сложным и тонким. Для иллюстрации я приведу довольно простой подход, но я предоставлю немного больше деталей , чтобы проиллюстрировать , почему это работает.
Прежде всего, что мы пытаемся сделать? Мы хотим преобразовать байтовое значение (или массив байтов) в строку, которая представляет шестнадцатеричное значение в ASCII. Итак, первый шаг - выяснить, что такое байт в Java:
Что это значит? Несколько вещей: во-первых, и самое главное, это означает, что мы работаем с 8-битными . Так, например, мы можем записать число 2 как 0000 0010. Однако, поскольку оно является дополнением до двух, мы пишем отрицательное число 2, например: 1111 1110. Что также означает, что преобразование в шестнадцатеричное является очень простым. То есть вы просто конвертируете каждый 4-битный сегмент прямо в гекс. Обратите внимание, что для понимания отрицательных чисел в этой схеме вам сначала нужно понять дополнение к двум. Если вы еще не понимаете дополнение к двум, вы можете прочитать отличное объяснение здесь: http://www.cs.cornell.edu/~tomf/notes/cps104/twoscomp.html
Преобразование дополнения до двух в Hex в целом
Как только число становится дополнением до двух, его очень просто преобразовать в гекс. В общем, преобразование из двоичного в шестнадцатеричное очень просто, и, как вы увидите в следующих двух примерах, вы можете перейти непосредственно от дополнения двух до шестнадцатеричного.
Примеры
Пример 1: конвертировать 2 в шестнадцатеричное.
1) Сначала преобразуйте 2 в двоичный код в дополнении до двух:
2) Теперь преобразуйте двоичный файл в гекс:
Пример 2: конвертировать -2 (в дополнении до двух) в шестнадцатеричное.
1) Сначала преобразуйте -2 в двоичный код в дополнении до двух:
2) Теперь преобразуйте в Hex:
Делать это в Java
Теперь, когда мы рассмотрели эту концепцию, вы обнаружите, что мы можем достичь того, чего хотим, с помощью простой маскировки и сдвига. Главное, что нужно понять, это то, что байт, который вы пытаетесь преобразовать, уже дополняет два. Вы не делаете это преобразование самостоятельно. Я думаю, что это серьезная путаница в этом вопросе. Возьмем для примера следующий байтовый массив:
Мы просто вручную конвертировали их в шестнадцатеричные, но как мы можем это сделать на Java? Вот как:
Шаг 1: Создайте StringBuffer для хранения наших вычислений.
Шаг 2. Изолируйте биты высшего порядка, преобразуйте их в шестнадцатеричные и добавьте в буфер.
Учитывая двоичное число 1111 1110, мы можем выделить биты более высокого порядка, сначала сместив их на 4, а затем обнулив оставшуюся часть числа. Логически это просто, однако детали реализации в Java (и многих языках) вносят помехи из-за расширения знака. По сути, когда вы сдвигаете значение байта, Java сначала преобразует ваше значение в целое число, а затем выполняет расширение знака. Таким образом, хотя вы ожидаете, что 1111 1110 >> 4 будет 0000 1111, в действительности на Java это представляется как дополнение к двум 0xFFFFFFFF!
Итак, возвращаясь к нашему примеру:
Затем мы можем выделить биты с помощью маски:
В Java мы можем сделать все это одним выстрелом:
Функция forDigit просто отображает переданное вами число на набор шестнадцатеричных чисел 0-F.
Шаг 3: Далее нам нужно выделить биты младшего разряда. Поскольку нужные нам биты уже находятся в правильном положении, мы можем просто замаскировать их:
Как и раньше, в Java мы можем сделать все это за один раз:
Собрав все это вместе, мы можем сделать это как цикл for и преобразовать весь массив:
Надеюсь, это объяснение прояснит ситуацию для тех, кто интересуется, что именно происходит во многих примерах, которые вы найдете в Интернете. Надеюсь, я не допустил вопиющих ошибок, но предложения и исправления приветствуются!
источник
Character.digit()
, как(byte) ((Character.digit(str.charAt(0), 16) << 4) + Character.digit(str.charAt(1), 16))
Самый быстрый способ, который я пока нашел, это сделать следующее:
Это ~ в 50 раз быстрее чем
String.format
. если вы хотите проверить это:Изменить : только что нашел что-то немного быстрее, и он держится на одной строке, но не совместим с JRE 9. Используйте на свой страх и риск
источник
printHexBinary
из src.zip из jdk, который кажется в 1 раз быстрее, чем первый метод.Попробуйте так:
Работа с массивом (если я вас правильно понял):
Как уже упоминалось, полигенные смазочные материалы
String.format()
- это правильный ответ по сравнению сInteger.toHexString()
(поскольку он правильно работает с отрицательными числами).источник
-1
.bv
этого возвращает один шестнадцатеричный символ . Принимая во внимание, что остальная часть кода возвращает строку шестнадцатеричных символов . Я изменил код с помощью разделителя, чтобы вы могли понять его сейчас.Integer.toHexString
если вы маскируетеbyte
с,0xFF
чтобы отменить расширение знака.Лучшее решение - это задира:
как упомянуто здесь
источник
new BigInteger(byteArray).toString(16)
это путь тогда. Есть ли проблемы с этим?Если вам нужно шестнадцатеричное представление постоянной ширины, т.е.
0A
вместоA
, чтобы вы могли однозначно восстановить байты, попробуйтеformat()
:источник
Короткий и простой способ преобразования
byte[]
в шестнадцатеричную строку с помощьюBigInteger
:Как это устроено?
Класс встроенного системного класса
java.math.BigInteger
( java.math.BigInteger ) совместим с двоичными и шестнадцатеричными данными:BigInteger(signum=1, byte[])
для создания большого целого числаbyte[]
(установите его первый параметрsignum
=1
для правильной обработки отрицательных байтов)BigInteger.toString(16)
для преобразования большого целого числа в шестнадцатеричную строкуnew BigInteger("ffa74b", 16)
- неправильно обрабатывает ведущий нольЕсли вы хотите иметь начальный ноль в шестнадцатеричном результате, проверьте его размер и добавьте недостающий ноль, если необходимо:
Ноты
Используйте
new BigInteger(1, bytes)
вместоnew BigInteger(bytes)
, потому что Java « разбита по дизайну », иbyte
тип данных не содержит байтов, но подписан крошечными целыми числами [-128 ... 127]. Если первый байт отрицательный,BigInteger
предполагается, что вы передаете отрицательное большое целое число. Просто передайте в1
качестве первого параметра (signum=1
).Обратное преобразование из шестнадцатеричного формата в
byte[]
хитрое: иногда в произведенный вывод входит ведущий ноль, и его следует очистить так:Последнее замечание: если у
byte[]
него несколько ведущих нулей, они будут потеряны.источник
Если вы счастливы использовать внешнюю библиотеку, у
org.apache.commons.codec.binary.Hex
класса естьencodeHex
метод, который принимаетbyte[]
и возвращает achar[]
. Этот метод НАМНОГО быстрее, чем опция формата, и включает в себя детали преобразования. Также поставляется сdecodeHex
методом для обратного преобразования.источник
javax
пространство имен не всегда доступно.Вы можете использовать метод из библиотеки Bouncy Castle Provider :
Maven зависимость:
или из кодека Apache Commons :
Maven зависимость:
источник
Это код, который я нашел для запуска быстрее всего. Я запускал его на 109015 байтовых массивах длиной 32 в 23 мс. Я запускал его на виртуальной машине, так что, вероятно, он будет работать быстрее на голом металле.
Тогда вы можете просто сделать
источник
источник
BigInteger(byteArrayOf(-1, 2, 3, 4, 5)).toString(16)
возвращается"-fdfcfbfb"
(int) 255
), поскольку байты Java подписаны, поэтому результат должен бытьFF02030405
. Если вы попробуете решение @Jerinaw выше, вы увидите, что оно выведет правильный вывод. Также см. Решение Светлина Накова ниже.Вот простая функция для преобразования байта в шестнадцатеричный
источник
Другие охватили общий случай. Но если у вас есть байтовый массив известной формы, например, MAC-адрес, то вы можете:
источник
Создание (и уничтожение) группы
String
экземпляров не является хорошим способом, если производительность является проблемой.Пожалуйста, игнорируйте эти подробные (повторяющиеся) аргументы, проверяющие операторы
if
. Это для (других) образовательных целей.Полный проект Maven: http://jinahya.googlecode.com/svn/trunk/com.googlecode.jinahya/hex-codec/
Кодирование ...
Декодирование ...
источник
Это очень быстрый способ. Внешние библиотеки не нужны.
источник
Я не мог понять, что именно вы имели в виду под байтовой строкой, но вот некоторые преобразования из байтовой в строковую и наоборот, конечно, в официальных документах намного больше
Соответствующее значение байта:
получить целочисленное значение из байтовой переменной:
От байта и целого до шестнадцатеричной строки:
так я делаю:
Преобразование массива байтов в шестнадцатеричную строку.
Насколько я знаю, не существует простой функции для преобразования всех элементов в одном массиве
Object
в элементы другогоObject
, поэтому вы должны сделать это самостоятельно. Вы можете использовать следующие функции:От байта [] к строке:
И из шестнадцатеричной строки в байт []:
Слишком поздно, но я надеюсь, что это может помочь другим;)
источник
Вот ваш быстрый метод:
источник
Как и некоторые другие ответы, я рекомендую использовать
String.format()
иBigInteger
. Но для интерпретации байтового массива как двоичного представления с прямым порядком байтов вместо двоичного представления с двумя дополнительными значениями (с сигнумом и неполным использованием диапазона возможных шестнадцатеричных значений) используйте BigInteger (int signum, byte [] magnitude) , а не BigInteger (byte [] val ) .Например, для байтового массива длиной 8 используйте:
Преимущества:
Недостаток:
Пример:
Пример вывода:
источник
использование
источник