Utiliser un tableau d’octets comme clé de carte

Voyez-vous un problème avec l’utilisation d’un tableau d’octets en tant que clé Map? Je pourrais aussi faire de new Ssortingng(byte[]) et hash by Ssortingng mais il est plus simple d’utiliser byte[] .

Le problème est que l’ byte[] utilise l’identité d’object pour les equals et le hashCode , de sorte que

 byte[] b1 = {1, 2, 3} byte[] b2 = {1, 2, 3} 

ne correspondra pas dans un HashMap . Je vois trois options:

  1. Envelopper une Ssortingng , mais vous devez faire attention aux problèmes d’encodage (vous devez vous assurer que l’octet -> chaîne -> octet vous donne les mêmes octets).
  2. Utilisez List (peut être coûteux en mémoire).
  3. Faites votre propre classe d’emballage, en écrivant hashCode et equals à utiliser le contenu du tableau d’octets.

Ce n’est pas grave tant que vous ne voulez qu’une égalité de référence pour vos clés – les tableaux n’implémentent pas “l’égalité de valeur” comme vous le voudriez probablement. Par exemple:

 byte[] array1 = new byte[1]; byte[] array2 = new byte[1]; System.out.println(array1.equals(array2)); System.out.println(array1.hashCode()); System.out.println(array2.hashCode()); 

imprime quelque chose comme:

 false 1671711 11394033 

(Les nombres réels ne sont pas pertinents; le fait qu’ils soient différents est important.)

En supposant que vous voulez réellement l’ égalité, je vous suggère de créer votre propre wrapper qui contient un byte[] et implémente de manière appropriée l’égalité et la génération de code de hachage:

 public final class ByteArrayWrapper { private final byte[] data; public ByteArrayWrapper(byte[] data) { if (data == null) { throw new NullPointerException(); } this.data = data; } @Override public boolean equals(Object other) { if (!(other instanceof ByteArrayWrapper)) { return false; } return Arrays.equals(data, ((ByteArrayWrapper)other).data); } @Override public int hashCode() { return Arrays.hashCode(data); } } 

Notez que si vous modifiez les valeurs dans le tableau d’octets après avoir utilisé ByteArrayWrapper , en tant que clé dans un HashMap (etc), vous aurez de la difficulté à rechercher la clé à nouveau … vous pouvez en prendre une copie dans le constructeur ByteArrayWrapper si vous voulez, mais évidemment, ce sera une perte de performance si vous savez que vous ne changerez pas le contenu du tableau d’octets.

EDIT: Comme mentionné dans les commentaires, vous pouvez également utiliser ByteBuffer pour cela (en particulier, sa ByteBuffer#wrap(byte[]) ). Je ne sais pas si c’est vraiment la bonne chose, compte tenu de toutes les capacités supplémentaires dont ByteBuffer a besoin, mais c’est une option.

Nous pouvons utiliser ByteBuffer pour cela (il s’agit essentiellement du wrapper octet [] avec un comparateur)

 HashMap kvs = new HashMap(); byte[] k1 = new byte[]{1,2 ,3}; byte[] k2 = new byte[]{1,2 ,3}; byte[] val = new byte[]{12,23,43,4}; kvs.put(ByteBuffer.wrap(k1), val); System.out.println(kvs.containsKey(ByteBuffer.wrap(k2))); 

imprimera

 true 

Vous pouvez utiliser java.math.BigInteger . Il a un constructeur BigInteger(byte[] val) . C’est un type de référence, il pourrait donc être utilisé comme clé pour la hashtable. Et .equals() et .hashCode() sont définis comme pour les nombres entiers respectifs, ce qui signifie que BigInteger a la même sémantique que byte [].

Je suis très surpris que les réponses n’indiquent pas l’alternative la plus simple.

Oui, il n’est pas possible d’utiliser un HashMap, mais personne ne vous empêche d’utiliser une SortedMap comme alternative. La seule chose est d’écrire un comparateur qui doit comparer les tableaux. Il n’est pas aussi performant qu’un HashMap, mais si vous voulez une alternative simple, vous pouvez y aller (vous pouvez remplacer SortedMap par Map si vous souhaitez masquer l’implémentation):

  private SortedMap testMap = new TreeMap<>(new ArrayComparator()); private class ArrayComparator implements Comparator { @Override public int compare(int[] o1, int[] o2) { int result = 0; int maxLength = Math.max(o1.length, o2.length); for (int index = 0; index < maxLength; index++) { int o1Value = index < o1.length ? o1[index] : 0; int o2Value = index < o2.length ? o2[index] : 0; int cmp = Integer.compare(o1Value, o2Value); if (cmp != 0) { result = cmp; break; } } return result; } } 

Cette implémentation peut être ajustée pour d'autres tableaux, la seule chose que vous devez savoir est que les tableaux égaux (= longueur égale avec des membres égaux) doivent renvoyer 0 et que vous avez un ordre déterminé

Je crois que les tableaux en Java n’implémentent pas nécessairement les méthodes hashCode() et equals(Object) intuitivement. C’est-à-dire que deux tableaux d’octets identiques ne partageront pas nécessairement le même code de hachage et ne prétendront pas nécessairement être égaux. Sans ces deux caractéristiques, votre HashMap se comportera de manière inattendue.

Par conséquent, je déconseille d’utiliser l’ byte[] comme clé dans un HashMap.

Vous devez utiliser create une classe comme ByteArrKey et surcharger le hashcode et les méthodes égales, mémoriser le contrat entre eux.

Cela vous donnera une plus grande flexibilité, car vous pouvez ignorer 0 entrées ajoutées à la fin du tableau d’octets, surtout si vous ne copiez qu’une partie de l’autre tampon d’octets.

De cette façon, vous déciderez comment les deux objects DEVRAIENT être égaux.

Je vois des problèmes car vous devez utiliser Arrays.equals et Array.hashCode, à la place des implémentations de tableaux par défaut

Arrays.toSsortingng (bytes)

Vous pouvez également convertir l’octet [] en une chaîne «sûre» à l’aide de Base32 ou Base64, par exemple:

 byte[] keyValue = new byte[] {…}; Ssortingng key = javax.xml.bind.DatatypeConverter.printBase64Binary(keyValue); 

Bien sûr, il existe de nombreuses variantes de ce qui précède, comme:

 Ssortingng key = org.apache.commons.codec.binary.Base64.encodeBase64(keyValue); 

Voici une solution utilisant TreeMap, l’interface Comparator et la méthode java java.util.Arrays.equals (byte [], byte []);

REMARQUE: le classement dans la carte n’est pas pertinent avec cette méthode

 SortedMap testMap = new TreeMap<>(new ArrayComparator()); static class ArrayComparator implements Comparator { @Override public int compare(byte[] byteArray1, byte[] byteArray2) { int result = 0; boolean areEquals = Arrays.equals(byteArray1, byteArray2); if (!areEquals) { result = -1; } return result; } }