Как преобразовать массив байтов в шестнадцатеричную строку в Java?

У меня есть массив байтов, заполненный шестнадцатеричными числами, и его легко печатать легко, потому что есть много непечатаемых элементов. Мне нужен именно точный hexcode в виде: 3a5f771c

Ответ 1

Из обсуждения здесь, и особенно из этого ответа, я использую эту функцию:

private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
public static String bytesToHex(byte[] bytes) {
    char[] hexChars = new char[bytes.length * 2];
    for (int j = 0; j < bytes.length; j++) {
        int v = bytes[j] & 0xFF;
        hexChars[j * 2] = HEX_ARRAY[v >>> 4];
        hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
    }
    return new String(hexChars);
}

Мои собственные крошечные тесты (миллион байтов в тысячу раз, 256 байтов в 10 миллионов раз) показали, что он намного быстрее, чем любая другая альтернатива, примерно вдвое меньше для длинных массивов. По сравнению с ответом, который я получил, переключение на побитовые операции - как предлагалось в обсуждении - сократило время на длинные массивы примерно на 20%. (Изменение: когда я говорю это быстрее, чем альтернативы, я имею в виду альтернативный код, предлагаемый в обсуждениях. Производительность эквивалентна кодеку Commons, который использует очень похожий код.)

Ответ 2

В библиотеке Apache Commons Codec есть класс Hex для выполнения именно этого типа работы.

import org.apache.commons.codec.binary.Hex;

String foo = "I am a string";
byte[] bytes = foo.getBytes();
System.out.println( Hex.encodeHexString( bytes ) );

Ответ 3

Метод javax.xml.bind.DatatypeConverter.printHexBinary(), являющийся частью Java Architecture для привязки XML (JAXB), был удобным способом преобразования byte[] в шестнадцатеричную строку. В класс DatatypeConverter также включены многие другие полезные методы манипулирования данными A-.

В Java 8 и более ранних версиях JAXB был частью стандартной библиотеки Java. Это было устарело с Java 9 и удалено с Java 11, как часть попытки переместить все пакеты Java EE в свои собственные библиотеки. Это долгая история. Теперь javax.xml.bind не существует, и если вы хотите использовать JAXB, который содержит DatatypeConverter, вам необходимо установить JAXB API и JAXB Runtime от Maven.

Пример использования:

byte bytes[] = {(byte)0, (byte)0, (byte)134, (byte)0, (byte)61};
String hex = javax.xml.bind.DatatypeConverter.printHexBinary(bytes);

В результате:

000086003D

Этот ответ такой же, как этот.

Ответ 4

Простейшее решение, без внешних библиотек, без цифр:

public static String byteArrayToHex(byte[] a) {
   StringBuilder sb = new StringBuilder(a.length * 2);
   for(byte b: a)
      sb.append(String.format("%02x", b));
   return sb.toString();
}

Ответ 5

Решение Guava для полноты:

import com.google.common.io.BaseEncoding;
...
byte[] bytes = "Hello world".getBytes(StandardCharsets.UTF_8);
final String hex = BaseEncoding.base16().lowerCase().encode(bytes);

Теперь hex есть "48656c6c6f20776f726c64".

Ответ 6

Этот простой oneliner работает для меня
  String result = new BigInteger(1, inputBytes).toString(16);
EDIT - использование этого приведет к удалению ведущих нулей, но эй работал на мой прецедент. Спасибо @Voicu за указание на него

Ответ 7

Использовать класс DataTypeConverter javax.xml.bind.DataTypeConverter

String hexString = DatatypeConverter.printHexBinary(bytes[] raw);

Ответ 8

Я бы использовал что-то вроде этого для фиксированной длины, например хэши:

md5sum = String.format("%032x", new BigInteger(1, md.digest()));

Ответ 9

Я нашел здесь три разных способа: http://www.rgagnon.com/javadetails/java-0596.html

Самый изящный, как он также отмечает, я думаю, что это:

static final String HEXES = "0123456789ABCDEF";
public static String getHex( byte [] raw ) {
    if ( raw == null ) {
        return null;
    }
    final StringBuilder hex = new StringBuilder( 2 * raw.length );
    for ( final byte b : raw ) {
        hex.append(HEXES.charAt((b & 0xF0) >> 4))
            .append(HEXES.charAt((b & 0x0F)));
    }
    return hex.toString();
}

Ответ 10

При незначительной стоимости хранения таблицы поиска эта реализация проста и очень быстра.

 private static final char[] BYTE2HEX=(
    "000102030405060708090A0B0C0D0E0F"+
    "101112131415161718191A1B1C1D1E1F"+
    "202122232425262728292A2B2C2D2E2F"+
    "303132333435363738393A3B3C3D3E3F"+
    "404142434445464748494A4B4C4D4E4F"+
    "505152535455565758595A5B5C5D5E5F"+
    "606162636465666768696A6B6C6D6E6F"+
    "707172737475767778797A7B7C7D7E7F"+
    "808182838485868788898A8B8C8D8E8F"+
    "909192939495969798999A9B9C9D9E9F"+
    "A0A1A2A3A4A5A6A7A8A9AAABACADAEAF"+
    "B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"+
    "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF"+
    "D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF"+
    "E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF"+
    "F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF").toCharArray();
   ; 

  public static String getHexString(byte[] bytes) {
    final int len=bytes.length;
    final char[] chars=new char[len<<1];
    int hexIndex;
    int idx=0;
    int ofs=0;
    while (ofs<len) {
      hexIndex=(bytes[ofs++] & 0xFF)<<1;
      chars[idx++]=BYTE2HEX[hexIndex++];
      chars[idx++]=BYTE2HEX[hexIndex];
    }
    return new String(chars);
  }

Ответ 11

Как насчет этого?

    String byteToHex(final byte[] hash)
    {
        Formatter formatter = new Formatter();
        for (byte b : hash)
        {
            formatter.format("%02x", b);
        }
        String result = formatter.toString();
        formatter.close();
        return result;
    }

Ответ 12

Вот несколько общих опций, упорядоченных от простого (однострочный) до сложного (огромная библиотека).

Вариант 1. Фрагмент кода - Простой

Одно очень простое решение - использовать шестнадцатеричное представление BigInteger:

new BigInteger(1, someByteArray).toString(16)

Обратите внимание, что поскольку он обрабатывает числа, а не произвольные строки байтов, он пропускает начальные нули - это может или не может быть тем, что вы хотите (например, 000AE3 против 0AE3). Это также очень медленно, примерно в 50 раз медленнее по сравнению со следующим вариантом.

Вариант 2. Фрагмент кода - расширенный

Вот полнофункциональный фрагмент кода, поддерживающий верхний/нижний регистр и порядковый номер. Он оптимизирован для минимизации сложности памяти и максимальной производительности и должен быть совместим со всеми современными версиями Java (5+).

private static final char[] LOOKUP_TABLE_LOWER = new char[]{0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66};
private static final char[] LOOKUP_TABLE_UPPER = new char[]{0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46};

public static String encode(byte[] byteArray, boolean upperCase, ByteOrder byteOrder) {

    // our output size will be exactly 2x byte-array length
    final char[] buffer = new char[byteArray.length * 2];

    // choose lower or uppercase lookup table
    final char[] lookup = upperCase ? LOOKUP_TABLE_UPPER : LOOKUP_TABLE_LOWER;

    int index;
    for (int i = 0; i < byteArray.length; i++) {
        // for little endian we count from last to first
        index = (byteOrder == ByteOrder.BIG_ENDIAN) ? i : byteArray.length - i - 1;

        // extract the upper 4 bit and look up char (0-A)
        buffer[i << 1] = lookup[(byteArray[index] >> 4) & 0xF];
        // extract the lower 4 bit and look up char (0-A)
        buffer[(i << 1) + 1] = lookup[(byteArray[index] & 0xF)];
    }
    return new String(buffer);
}

public static String encode(byte[] byteArray) {
    return encode(byteArray, false, ByteOrder.BIG_ENDIAN);
}

По сути, он использует код из варианта 3. Если вы хотите увидеть микро-тест JMH, сравнивающий несколько реализаций, см. здесь. Полный исходный код с лицензией и декодером Apache v2 можно найти здесь.

Вариант 3. Использование небольшой оптимизированной библиотеки: bytes-java

Работая над моим предыдущим проектом, я создал этот небольшой инструментарий для работы с байтами в Java. Он не имеет внешних зависимостей и совместим с Java 7+. Он включает, среди прочего, очень быстрый и хорошо протестированный HEX en/decoder:

import at.favre.lib.bytes.Bytes;
...
Bytes.wrap(someByteArray).encodeHex()

Вы можете проверить это на Github: bytes-java.

Вариант 4. Кодек Apache Commons

Конечно, есть хорошие общие кодеки. (предупреждающее мнение впереди) Во время работы над проектом, описанным выше, я проанализировал код и был весьма разочарован; множество дублированных неорганизованных кодов, устаревших и экзотических кодеков, вероятно, полезно только для очень немногих и довольно изощренных и медленных реализаций популярных кодеков (особенно Base64). Поэтому я бы принял обоснованное решение, если вы хотите использовать его или альтернативу. В любом случае, если вы все еще хотите его использовать, вот фрагмент кода:

import org.apache.commons.codec.binary.Hex;
...
Hex.encodeHexString(someByteArray));

Вариант 5: Google Guava

Чаще всего у вас уже есть Guava в качестве зависимости. Если это так, просто используйте:

import com.google.common.io.BaseEncoding;
...
BaseEncoding.base16().lowerCase().encode(someByteArray);

Вариант 6: Spring Security

Если вы используете Spring Framework с Spring Security, вы можете использовать следующее:

import org.springframework.security.crypto.codec.Hex
...
Hex.encode(someByteArray);

Совместимость с Java 9 или "Не используйте JAXBs javax/xml/bind/DatatypeConverter"

В предыдущих версиях Java (8 и ниже) код Java для JAXB был включен как зависимость времени выполнения. Начиная с Java 9 и Jigsaw modularisation ваш код не может получить доступ к другому коду вне его модуля. Так что будьте внимательны, если вы получите исключение, например:

java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException

при работе на JVM с Java 9+. Если это так, то переключите реализации на любую из альтернатив, описанных выше. Смотрите также этот вопрос.

Ответ 13

Обычно я использую следующий метод для инструкции debuf, но я не знаю, является ли это лучшим способом сделать это или нет.

private static String digits = "0123456789abcdef";

public static String toHex(byte[] data){
    StringBuffer buf = new StringBuffer();
    for (int i = 0; i != data.length; i++)
    {
        int v = data[i] & 0xff;
        buf.append(digits.charAt(v >> 4));
        buf.append(digits.charAt(v & 0xf));
    }
    return buf.toString();
}

Ответ 14

Я предпочитаю использовать это:

final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
public static String bytesToHex(byte[] bytes, int offset, int count) {
    char[] hexChars = new char[count * 2];
    for ( int j = 0; j < count; j++ ) {
        int v = bytes[j+offset] & 0xFF;
        hexChars[j * 2] = hexArray[v >>> 4];
        hexChars[j * 2 + 1] = hexArray[v & 0x0F];
    }
    return new String(hexChars);
}

Это немного более гибкая адаптация принятого ответа. Лично я сохраняю как принятый ответ, так и эту перегрузку вместе с ним, можно использовать в других контекстах.

Ответ 15

Хорошо, поэтому есть несколько способов сделать это, но если вы решите использовать библиотеку, я бы предложил заглянуть в ваш проект, чтобы увидеть, было ли что-то реализовано в библиотеке, которая уже является частью вашего проекта, перед добавлением это новая библиотека. Например, если у вас еще нет

org.apache.commons.codec.binary.Hex

возможно, у вас есть...

org.apache.xerces.impl.dv.util.HexBin

Ответ 16

Если вы используете платформу Spring Security, вы можете использовать:

import org.springframework.security.crypto.codec.Hex

final String testString = "Test String";
final byte[] byteArray = testString.getBytes();
System.out.println(Hex.encode(byteArray));

Ответ 17

Добавление утилиты jar для простой функции не является хорошим вариантом. Вместо этого соберите свои собственные служебные классы. Следующее возможно быстрее реализации.

public class ByteHex {

    public static int hexToByte(char ch) {
        if ('0' <= ch && ch <= '9') return ch - '0';
        if ('A' <= ch && ch <= 'F') return ch - 'A' + 10;
        if ('a' <= ch && ch <= 'f') return ch - 'a' + 10;
        return -1;
    }

    private static final String[] byteToHexTable = new String[]
    {
        "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B", "0C", "0D", "0E", "0F",
        "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1A", "1B", "1C", "1D", "1E", "1F",
        "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F",
        "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B", "3C", "3D", "3E", "3F",
        "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4A", "4B", "4C", "4D", "4E", "4F",
        "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F",
        "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B", "6C", "6D", "6E", "6F",
        "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7A", "7B", "7C", "7D", "7E", "7F",
        "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F",
        "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B", "9C", "9D", "9E", "9F",
        "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF",
        "B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF",
        "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB", "CC", "CD", "CE", "CF",
        "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF",
        "E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF",
        "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF"
    };

    private static final String[] byteToHexTableLowerCase = new String[]
    {
        "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0a", "0b", "0c", "0d", "0e", "0f",
        "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1a", "1b", "1c", "1d", "1e", "1f",
        "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2a", "2b", "2c", "2d", "2e", "2f",
        "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3a", "3b", "3c", "3d", "3e", "3f",
        "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4a", "4b", "4c", "4d", "4e", "4f",
        "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5a", "5b", "5c", "5d", "5e", "5f",
        "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6a", "6b", "6c", "6d", "6e", "6f",
        "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7a", "7b", "7c", "7d", "7e", "7f",
        "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8a", "8b", "8c", "8d", "8e", "8f",
        "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9a", "9b", "9c", "9d", "9e", "9f",
        "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "aa", "ab", "ac", "ad", "ae", "af",
        "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8", "b9", "ba", "bb", "bc", "bd", "be", "bf",
        "c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "ca", "cb", "cc", "cd", "ce", "cf",
        "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "da", "db", "dc", "dd", "de", "df",
        "e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7", "e8", "e9", "ea", "eb", "ec", "ed", "ee", "ef",
        "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "fa", "fb", "fc", "fd", "fe", "ff"
    };

    public static String byteToHex(byte b){
        return byteToHexTable[b & 0xFF];
    }

    public static String byteToHex(byte[] bytes){
        if(bytes == null) return null;
        StringBuilder sb = new StringBuilder(bytes.length*2);
        for(byte b : bytes) sb.append(byteToHexTable[b & 0xFF]);
        return sb.toString();
    }

    public static String byteToHex(short[] bytes){
        StringBuilder sb = new StringBuilder(bytes.length*2);
        for(short b : bytes) sb.append(byteToHexTable[((byte)b) & 0xFF]);
        return sb.toString();
    }

    public static String byteToHexLowerCase(byte[] bytes){
        StringBuilder sb = new StringBuilder(bytes.length*2);
        for(byte b : bytes) sb.append(byteToHexTableLowerCase[b & 0xFF]);
        return sb.toString();
    }

    public static byte[] hexToByte(String hexString) {
        if(hexString == null) return null;
        byte[] byteArray = new byte[hexString.length() / 2];
        for (int i = 0; i < hexString.length(); i += 2) {
            byteArray[i / 2] = (byte) (hexToByte(hexString.charAt(i)) * 16 + hexToByte(hexString.charAt(i+1)));
        }
        return byteArray;
    }

    public static byte hexPairToByte(char ch1, char ch2) {
        return (byte) (hexToByte(ch1) * 16 + hexToByte(ch2));
    }


}

Ответ 18

Небольшой вариант решения, предложенный @maybewecouldstealavan, который позволяет визуально связывать N байтов вместе в выходной шестнадцатеричной строке:

 final static char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
 final static char BUNDLE_SEP = ' ';

public static String bytesToHexString(byte[] bytes, int bundleSize /*[bytes]*/]) {
        char[] hexChars = new char[(bytes.length * 2) + (bytes.length / bundleSize)];
        for (int j = 0, k = 1; j < bytes.length; j++, k++) {
                int v = bytes[j] & 0xFF;
                int start = (j * 2) + j/bundleSize;

                hexChars[start] = HEX_ARRAY[v >>> 4];
                hexChars[start + 1] = HEX_ARRAY[v & 0x0F];

                if ((k % bundleSize) == 0) {
                        hexChars[start + 2] = BUNDLE_SEP;
                }   
        }   
        return new String(hexChars).trim();    
}

То есть:

bytesToHexString("..DOOM..".toCharArray().getBytes(), 2);
2E2E 444F 4F4D 2E2E

bytesToHexString("..DOOM..".toCharArray().getBytes(), 4);
2E2E444F 4F4D2E2E

Ответ 19

Не удается найти решение на этой странице,

  1. Использовать цикл
  2. Используйте javax.xml.bind.DatatypeConverter, который компилируется отлично, но часто вызывает java.lang.NoClassDefFoundError во время выполнения.

Здесь решение, которое не имеет недостатков выше (никаких обещаний у меня нет других недостатков)

import java.math.BigInteger;

import static java.lang.System.out;
public final class App2 {
    // | proposed solution.
    public static String encode(byte[] bytes) {          
        final int length = bytes.length;

        // | BigInteger constructor throws if it is given an empty array.
        if (length == 0) {
            return "00";
        }

        final int evenLength = (int)(2 * Math.ceil(length / 2.0));
        final String format = "%0" + evenLength + "x";         
        final String result = String.format (format, new BigInteger(bytes));

        return result;
    }

    public static void main(String[] args) throws Exception {
        // 00
        out.println(encode(new byte[] {})); 

        // 01
        out.println(encode(new byte[] {1})); 

        //203040
        out.println(encode(new byte[] {0x20, 0x30, 0x40})); 

        // 416c6c20796f75722062617365206172652062656c6f6e6720746f2075732e
        out.println(encode("All your base are belong to us.".getBytes()));
    }
}   

Я не мог получить это под 62 опкодами, но если вы можете жить без 0 дополнений, если первый байт меньше 0x10, тогда следующее решение использует только 23 кода операций. На самом деле показывает, как "простые для реализации" решения, такие как "pad с нулевым значением, если длина строки нечетна", могут стать довольно дорогими, если собственная реализация еще не доступна (или в этом случае, если BigInteger имел возможность префикса с нулями в нанизывать).

public static String encode(byte[] bytes) {          
    final int length = bytes.length;

    // | BigInteger constructor throws if it is given an empty array.
    if (length == 0) {
        return "00";
    }

    return new BigInteger(bytes).toString(16);
}

Ответ 20

Мое решение основано на возможном решении WeCouldStealAVan, но не полагается на какие-либо дополнительные распределенные таблицы поиска. Он не использует хакеры "int-to-char" (на самом деле, Character.forDigit() делает это, выполняя некоторое сравнение, чтобы проверить, что действительно цифра) и, следовательно, может быть немного медленнее. Пожалуйста, не стесняйтесь использовать его там, где хотите. Приветствия.

public static String bytesToHex(final byte[] bytes)
{
    final int numBytes = bytes.length;
    final char[] container = new char[numBytes * 2];

    for (int i = 0; i < numBytes; i++)
    {
        final int b = bytes[i] & 0xFF;

        container[i * 2] = Character.forDigit(b >>> 4, 0x10);
        container[i * 2 + 1] = Character.forDigit(b & 0xF, 0x10);
    }

    return new String(container);
}

Ответ 21

//Сдвиг байтов более эффективен // Вы также можете использовать эту функцию

public static String getHexString (String s) 
{
    byte[] buf = s.getBytes();

    StringBuffer sb = new StringBuffer();

    for (byte b:buf)
    {
        sb.append(String.format("%x", b));
    }


        return sb.toString();
}

Ответ 22

Если вы ищете массив байтов точно так же, как для python, я преобразовал эту реализацию Java в python.

class ByteArray:

@classmethod
def char(cls, args=[]):
    cls.hexArray = "0123456789ABCDEF".encode('utf-16')
    j = 0
    length = (cls.hexArray)

    if j < length:
        v = j & 0xFF
        hexChars = [None, None]
        hexChars[j * 2] = str( cls.hexArray) + str(v)
        hexChars[j * 2 + 1] = str(cls.hexArray) + str(v) + str(0x0F)
        # Use if you want...
        #hexChars.pop()

    return str(hexChars)

array = ByteArray()
print array.char(args=[])

Ответ 23

  public static byte[] hexStringToByteArray(String s) {
    int len = s.length();
    byte[] data = new byte[len / 2];
    for (int i = 0; i < len; i += 2) {
      data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
        + Character.digit(s.charAt(i+1), 16));
    }
  return data;
  } 

Ответ 24

Здесь java.util.Base64 -подобная реализация (частичная), не так ли?

public class Base16/*a.k.a. Hex*/ {
    public static class Encoder{
        private static char[] toLowerHex={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
        private static char[] toUpperHex={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
        private boolean upper;
        public Encoder(boolean upper) {
            this.upper=upper;
        }
        public String encode(byte[] data){
            char[] value=new char[data.length*2];
            char[] toHex=upper?toUpperHex:toLowerHex;
            for(int i=0,j=0;i<data.length;i++){
                int octet=data[i]&0xFF;
                value[j++]=toHex[octet>>4];
                value[j++]=toHex[octet&0xF];
            }
            return new String(value);
        }
        static final Encoder LOWER=new Encoder(false);
        static final Encoder UPPER=new Encoder(true);
    }
    public static Encoder getEncoder(){
        return Encoder.LOWER;
    }
    public static Encoder getUpperEncoder(){
        return Encoder.UPPER;
    }
    //...
}

Ответ 25

private static String bytesToHexString(byte[] bytes, int length) {
        if (bytes == null || length == 0) return null;

        StringBuilder ret = new StringBuilder(2*length);

        for (int i = 0 ; i < length ; i++) {
            int b;

            b = 0x0f & (bytes[i] >> 4);
            ret.append("0123456789abcdef".charAt(b));

            b = 0x0f & bytes[i];
            ret.append("0123456789abcdef".charAt(b));
        }

        return ret.toString();
    }

Ответ 26

          Converts bytes data to hex characters

          @param bytes byte array to be converted to hex string
          @return byte String in hex format

        private static String bytesToHex(byte[] bytes) {
            char[] hexChars = new char[bytes.length * 2];
            int v;
            for (int j = 0; j < bytes.length; j++) {
                v = bytes[j] & 0xFF;
                hexChars[j * 2] = HEX_ARRAY[v >>> 4];
                hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
            }
            return new String(hexChars);
        }