Voyez-vous un problème avec l'utilisation d'un tableau d'octets en tant que clé de la carte? Je pourrais aussi faire new String(byte[])
et hachage de String
mais il est plus simple d’utiliser byte[]
.
Le problème est que byte[]
utilise l'identité de l'objet pour equals
et hashCode
, de sorte que
byte[] b1 = {1, 2, 3}
byte[] b2 = {1, 2, 3}
ne correspondra pas à une HashMap
. Je vois trois options:
String
, mais ensuite vous devez faire attention aux problèmes d'encodage (vous devez vous assurer que l'octet -> String -> octet vous donne les mêmes octets).List<Byte>
(peut être coûteux en mémoire).hashCode
et equals
pour utiliser le contenu du tableau d'octets.Ce n'est pas grave tant que vous ne voulez que l'égalité de référence pour votre clé - les tableaux n'implémentent pas "l'égalité de valeur" comme vous le souhaiteriez 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 chiffres réels ne sont pas pertinents; le fait qu'ils soient différents est important.)
En supposant que vous désirez réellement , je vous suggère de créer votre propre wrapper contenant un byte[]
et de mettre en œuvre de manière appropriée la génération de code de hachage et d'égalité:
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é d'un HashMap
(etc.), vous aurez des problèmes pour rechercher la clé à nouveau ... copie des données dans le constructeur ByteArrayWrapper
si vous voulez, mais évidemment ce sera un gaspillage de performance si vous vous connaissez ne le serez pas être en train de changer le contenu du tableau d'octets.
EDIT: Comme mentionné dans les commentaires, vous pouvez également utiliser ByteBuffer
pour cela (en particulier, sa méthode ByteBuffer#wrap(byte[])
). Je ne sais pas si c'est vraiment la bonne chose, compte tenu de toutes les capacités supplémentaires dont dispose ByteBuffer
dont vous n'avez pas besoin, mais c'est une option.
Nous pouvons utiliser ByteBuffer pour cela (Il s’agit essentiellement du wrapper byte [] avec un comparateur)
HashMap<ByteBuffer, byte[]> kvs = new HashMap<ByteBuffer, byte[]>();
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, donc pourrait être utilisé comme clé pour hashtable. Et .equals()
et .hashCode()
sont définis comme pour les nombres entiers respectifs, ce qui signifie que BigInteger a une sémantique égale à égale sous forme de tableau 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 un SortedMap comme alternative. La seule chose à faire est d’écrire un comparateur qui doit comparer les tableaux. Ce n'est pas aussi performant qu'un HashMap, mais si vous voulez une alternative simple, le tour est joué (vous pouvez remplacer SortedMap par Map si vous voulez masquer l'implémentation):
private SortedMap<int[], String> testMap = new TreeMap<>(new ArrayComparator());
private class ArrayComparator implements Comparator<int[]> {
@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 les autres tableaux, la seule chose dont vous devez être conscient est que les tableaux égaux (= longueur égale avec membres égaux) doivent retourner 0 et que vous avez un ordre déterministe
Je pense que les tableaux Java n'implémentent pas nécessairement les méthodes hashCode()
et equals(Object)
de manière intuitive. En d'autres termes, 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 traits, votre HashMap se comportera de manière inattendue.
Par conséquent, je recommande contre en utilisant byte[]
comme clés dans un HashMap.
Vous devez utiliser create a somthing class, comme ByteArrKey, et surcharger le hashcode et les méthodes équivalentes, rappelez-vous le contrat qui les lie.
Cela vous donnera une plus grande flexibilité car vous pouvez ignorer les 0 entrées qui sont ajoutées à la fin du tableau d'octets, en particulier si vous ne copiez qu'une partie de l'autre tampon d'octets.
De cette façon, vous déciderez comment les deux objets DEVRAIENT être égaux.
Vous pouvez également convertir l'octet [] en une chaîne 'safe' utilisant Base32 ou Base64, par exemple:
byte[] keyValue = new byte[] {…};
String key = javax.xml.bind.DatatypeConverter.printBase64Binary(keyValue);
bien sûr, il existe de nombreuses variantes de ce qui précède, comme:
String 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: l'ordre dans la carte n'est pas pertinent avec cette méthode.
SortedMap<byte[], String> testMap = new TreeMap<>(new ArrayComparator());
static class ArrayComparator implements Comparator<byte[]> {
@Override
public int compare(byte[] byteArray1, byte[] byteArray2) {
int result = 0;
boolean areEquals = Arrays.equals(byteArray1, byteArray2);
if (!areEquals) {
result = -1;
}
return result;
}
}
Je vois des problèmes puisque vous devriez utiliser Arrays.equals et Array.hashCode, à la place des implémentations de tableaux par défaut
Arrays.toString (octets)
De plus, nous pouvons créer notre propre ByteHashMap personnalisé comme celui-ci,
ByteHashMap byteMap = new ByteHashMap();
byteMap.put(keybyteArray,valueByteArray);
Voici l'implémentation complète
public class ByteHashMap implements Map<byte[], byte[]>, Cloneable,
Serializable {
private Map<ByteArrayWrapper, byte[]> internalMap = new HashMap<ByteArrayWrapper, byte[]>();
public void clear() {
internalMap.clear();
}
public boolean containsKey(Object key) {
if (key instanceof byte[])
return internalMap.containsKey(new ByteArrayWrapper((byte[]) key));
return internalMap.containsKey(key);
}
public boolean containsValue(Object value) {
return internalMap.containsValue(value);
}
public Set<Java.util.Map.Entry<byte[], byte[]>> entrySet() {
Iterator<Java.util.Map.Entry<ByteArrayWrapper, byte[]>> iterator = internalMap
.entrySet().iterator();
HashSet<Entry<byte[], byte[]>> hashSet = new HashSet<Java.util.Map.Entry<byte[], byte[]>>();
while (iterator.hasNext()) {
Entry<ByteArrayWrapper, byte[]> entry = iterator.next();
hashSet.add(new ByteEntry(entry.getKey().data, entry
.getValue()));
}
return hashSet;
}
public byte[] get(Object key) {
if (key instanceof byte[])
return internalMap.get(new ByteArrayWrapper((byte[]) key));
return internalMap.get(key);
}
public boolean isEmpty() {
return internalMap.isEmpty();
}
public Set<byte[]> keySet() {
Set<byte[]> keySet = new HashSet<byte[]>();
Iterator<ByteArrayWrapper> iterator = internalMap.keySet().iterator();
while (iterator.hasNext()) {
keySet.add(iterator.next().data);
}
return keySet;
}
public byte[] put(byte[] key, byte[] value) {
return internalMap.put(new ByteArrayWrapper(key), value);
}
@SuppressWarnings("unchecked")
public void putAll(Map<? extends byte[], ? extends byte[]> m) {
Iterator<?> iterator = m.entrySet().iterator();
while (iterator.hasNext()) {
Entry<? extends byte[], ? extends byte[]> next = (Entry<? extends byte[], ? extends byte[]>) iterator
.next();
internalMap.put(new ByteArrayWrapper(next.getKey()), next
.getValue());
}
}
public byte[] remove(Object key) {
if (key instanceof byte[])
return internalMap.remove(new ByteArrayWrapper((byte[]) key));
return internalMap.remove(key);
}
public int size() {
return internalMap.size();
}
public Collection<byte[]> values() {
return internalMap.values();
}
private final class ByteArrayWrapper {
private final byte[] data;
public ByteArrayWrapper(byte[] data) {
if (data == null) {
throw new NullPointerException();
}
this.data = data;
}
public boolean equals(Object other) {
if (!(other instanceof ByteArrayWrapper)) {
return false;
}
return Arrays.equals(data, ((ByteArrayWrapper) other).data);
}
public int hashCode() {
return Arrays.hashCode(data);
}
}
private final class ByteEntry implements Entry<byte[], byte[]> {
private byte[] value;
private byte[] key;
public ByteEntry(byte[] key, byte[] value) {
this.key = key;
this.value = value;
}
public byte[] getKey() {
return this.key;
}
public byte[] getValue() {
return this.value;
}
public byte[] setValue(byte[] value) {
this.value = value;
return value;
}
}
}