Javaで整数型やbyte配列と16進表記の文字列との間の変換を行なう

こんにちは、エキサイト株式会社の平石です。エキサイトホールディングス Advent Calendar 2023の19日目を担当いたします。

今回は、Javaで整数型やbyte配列と16進表記の文字列との間の変換を行なう方法をご紹介します。

整数 → 16進表記 の変換

まずは、通常の10進表記(として表示される)整数を16進表記に変換してみます。

標準ライブラリのみを使う場合には、主に2つの方法があります。

IntegerやLongクラスのstaticメソッド

IntegerやLongクラスには、intやlongを16進表記に変換するstaticメソッドが用意されています。

var hexFromInt = Integer.toHexString(30);
var hexFromLong = Long.toHexString(255L);

System.out.println("30の16進表記: " + hexFromInt);
System.out.println("255Lの16進表記: " + hexFromLong);
30の16進表記: 1e
255Lの16進表記: ff

HexFormatクラスを使う

Java 17からはHexFormatクラスというものを利用することができます。

byte byteNum = 100;
short shortNum = 10000;
int intNum = 1000000;
long longNum = 100000000;

String hexFromByte = HexFormat.of().toHexDigits(byteNum);
String hexFromShort = HexFormat.of().toHexDigits(shortNum);
String hexFromInt = HexFormat.of().toHexDigits(intNum);
String hexFromLong = HexFormat.of().toHexDigits(longNum);

System.out.println("byteNumの16進表記: " + hexFromByte);
System.out.println("shortNumの16進表記: " + hexFromShort);
System.out.println("intNumの16進表記: " + hexFromInt);
System.out.println("longNumの16進表記: " + hexFromLong);
byteNumの16進表記: 64
shortNumの16進表記: 2710
intNumの16進表記: 000f4240
longNumの16進表記: 0000000005f5e100

このように、toHexDigitsに渡す引数の型によって最終的に出力される16進表記の長さも変わります。

Long型の整数は8バイトなので、1Lのような値を渡しても1ではなく0000000000000001が返ります。
一方、IntegerLongのstaticメソッドを利用するときには、1が返ります。
これが、この2つの方法の大きな違いですので、状況によって使い分けると良いでしょう。

HexFormatクラスについては後に詳しく紹介します。

16進表記 → 整数の変換

こちらも標準ライブラリのみを利用するのであれば、主に以下の2つの方法があります。

IntegerやLongクラスのstaticメソッド

IntegerやLongクラスのstaticメソッドを利用するには以下のようにします。

byte byteFromHex = Byte.parseByte("f", 16);
short shortFromHex = Short.parseShort("fff", 16);
int intFromHex = Integer.parseInt("fffff", 16);
long longFromHex = Long.parseLong("fffffff", 16);

System.out.println("f のパース結果: " + byteFromHex);
System.out.println("fff のパース結果: " + shortFromHex);
System.out.println("fffff のパース結果: " + intFromHex);
System.out.println("fffffff のパース結果: " + longFromHex);
f のパース結果: 15
fff のパース結果: 4095
fffff のパース結果: 1048575
fffffff のパース結果: 268435455

HexFormatクラスを使う

Java 17以降は、HexFormatクラスのstaticメソッドを利用しても、16進表記の文字列を整数に変換することができます。

int intFromHex = HexFormat.fromHexDigits("fffff");
long longFromHex = HexFormat.fromHexDigitsToLong("fffffff");
fffff のパース結果: 1048575
fffffff のパース結果: 268435455

HexFormatクラスによるbyte配列と16進表記の変換

HexFormatクラスを利用すれば、byte配列と16進表記の変換を行うことができます。

byte配列 → 16進表記

byte配列から16進表記の文字列に変換するには、formatHexメソッドを利用します。

byte[] bytes = {1, 15, 120, 127};
String byteHex = HexFormat.of().formatHex(bytes);

System.out.println(byteHex);
010f787f

ちなみに、負の数ではff(-1)から順に80(-128)となります。
(2の補数表現で-1は11111111なので当然といえば当然ですね。)

byte[] bytes = {-1, -2, -127, -128};
String byteHex = HexFormat.of().formatHex(bytes);
fffe8180

このメソッドを使って、ランダムな16進表記の文字列を作成できます。

final SecureRandom secureRandom = new SecureRandom();

final int numString = 64; // 生成したいランダムな文字列の文字数

final byte[] randomByte = new byte[numString / 2];
secureRandom.nextBytes(randomByte);

final String randomHex = HexFormat.of().formatHex(randomByte);

System.out.println(randomHex);

byte 1つにつき2文字に変換されるので、byte配列の長さはnumString / 2としています。

16進表記 → byte配列

逆に16進表記の文字列からbyte配列に変換するには、parseHexメソッドを利用します。
先ほどの例の変換後の文字列を、byte配列に戻してみましょう。

byte[] bytesFromHex = HexFormat.of().parseHex(byteHex); // byteHex = 010f787f

System.out.println(Arrays.toString(bytesFromHex));
[1, 15, 120, 127]

HexFormatクラスの詳細

最後に、HexFormatクラスの詳細についてみてみます。

これまでの例ではHexFormat.of()と書いてHexFormatインスタンスを取得していましたが、HexFormatインスタンスの取得のためにはofDelimiter()というstaticメソッドもあります。

of()delimiterなしのフォーマッター、ofDelimiter()delimitterありのフォーマッターを返します。

delimiterは、基本的には byte配列を16進表記に変換する際に区切り文字として使われます。 (toHexDigitsを使って単一のbyteや、int、longを変換する際には、delimiterは使われません。)

例えば、以下のように使います。

byte[] bytes = {1, 15, 120, 127};
String byteHex = HexFormat.ofDelimiter(":").formatHex(bytes);

System.out.println(byteHex);

byte[] bytesFromHex = HexFormat.ofDelimiter(":").parseHex(byteHex);

System.out.println(Arrays.toString(bytesFromHex));
01:0f:78:7f
[1, 15, 120, 127]

その他、HexFormatクラスのインスタンスに対しては、フォーマットの際の詳細設定を行うことができます。 prefix, suffix, delimiterはformatHexparseHexのみで利用されます。

  • withDelimiter・・・・delimiterを改めて指定できる
  • withLowerCase・・・16進表記に小文字(a ~ f)を使用するようになる
  • withUpperCase・・・16進表記に大文字(A ~ F)を使用するようになる
  • withPrefix・・・・・prefixを指定
  • withSuffix・・・・・suffixを指定
HexFormat hexFormat = HexFormat.of()
                .withDelimiter(", ")
                .withPrefix("#")
                .withSuffix(";")
                .withUpperCase();

byte[] bytes = {1, 15, 120, 127};

String hex = hexFormat.formatHex(bytes);
System.out.println(hex);

System.out.println(hexFormat.toHexDigits(255)); 
#01;, #0F;, #78;, #7F; // prefix, suffix, delimiterが適用される
000000FF // 単一の値の変換ではprefix, suffix, delimiterは適用されない

終わりに

今回は、Javaで整数型やbyte配列と16進表記の文字列との間の変換方法をご紹介しました。

では、また次回。

参考文献