Domanda

Vedi qualche problema con l'utilizzo di un array di byte come chiave della mappa?potrei anche farlo new String(byte[]) e hash da String ma è più semplice da usare byte[].

È stato utile?

Soluzione

Il problema è che byte[] utilizza identità di un oggetto per equals e hashCode, in modo che

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

non corrisponderà in un HashMap. Vedo tre opzioni:

  1. Wrapping in un String, ma poi si deve stare attenti a codifica problemi (è necessario accertarsi che il byte -> String -> byte ti dà la stessa byte).
  2. Usa List<Byte> (può essere costoso in memoria).
  3. Fare la propria classe di confezionamento, la scrittura e <=> <=> di utilizzare i contenuti della matrice di byte.

Altri suggerimenti

Va bene fintanto desideri solo l'uguaglianza di riferimento per la chiave - gli array non implementano "uguaglianza valore" nel modo in cui si sarebbe probabilmente desidera. Ad esempio:

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());

stampa qualcosa come:

false
1671711
11394033

(I numeri reali sono irrilevanti, il fatto che sono diversi è importante).

Supponendo di effettivamente vogliono l'uguaglianza, ti suggerisco di creare il proprio involucro che contiene un byte[] e realizza l'uguaglianza e la generazione di codice hash in modo appropriato:

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);
    }
}

Si noti che se si modificano i valori all'interno della matrice di byte dopo aver usato il ByteArrayWrapper, come una chiave in un HashMap (ecc) avrete problemi alzando la chiave di nuovo ... si potrebbe prendere una copia dei dati nel costruttore ByteBuffer se si vuole, ma, ovviamente, che sarà uno spreco di prestazioni se si sa che si nON stia cambiando il contenuto della matrice di byte.

EDIT: Come accennato nei commenti, si potrebbe anche usare ByteBuffer#wrap(byte[]) per questo (in particolare, la sua <=> metodo). Non so se è davvero la cosa giusta, dato tutte le abilità extra che <=> s hanno che non è necessario, ma è un'opzione.

Possiamo usare ByteBuffer per questo (Questo è fondamentalmente il byte [] involucro con un comparatore)

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)));

stamperà

true

Si potrebbe utilizzare java.math.BigInteger. Ha un costruttore BigInteger(byte[] val). È un tipo di riferimento, quindi potrebbe essere utilizzato come una chiave per tabella hash. E .equals() e .hashCode() sono definiti come per i rispettivi numeri interi, il che significa BigInteger trovi coerente uguale semantica byte [] array.

Sono molto sorpreso del fatto che le risposte non siano rivolte le più semplice alternativa.

Sì, non è possibile utilizzare un HashMap, ma nessuno vi impedisce di utilizzare un SortedMap come alternativa. L'unica cosa è scrivere un comparatore che ha bisogno di confrontare le matrici. Non è così performante come un HashMap, ma se volete una semplice alternativa, qui si va (si può sostituire con SortedMap mappa se si desidera nascondere l'attuazione):

 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;
    }
  }

Questa implementazione può essere regolata per altri array, l'unica cosa che si deve essere consapevoli è che le pari array (= uguale lunghezza con membri pari) devono restituire 0 e che avete un ordine DETERMISTIC

Credo che gli array in Java non implementino necessariamente il file hashCode() E equals(Object) metodi in modo intuitivo.Cioè, due array di byte identici non condivideranno necessariamente lo stesso codice hash e non affermeranno necessariamente di essere uguali.Senza queste due caratteristiche, la tua HashMap si comporterà in modo imprevisto.

Pertanto, lo consiglio contro utilizzando byte[] come chiavi in ​​una HashMap.

Si consiglia di utilizzare creare una classe di quacosa come ByteArrKey ed il sovraccarico codice hash e metodi uguali, ricorda il contratto tra loro.

Questo darà maggiore flessibilità è possibile saltare 0 voci che vengono aggiunti alla fine del byte, specialmente se si copia solo una parte forma l'altro buffer byte.

In questo modo potrete decidere come entrambi gli oggetti devono essere uguali.

Vedo problemi in quanto si dovrebbe usare Arrays.equals e Array.hashCode, al posto di implementazioni di array predefinito

Arrays.toString (byte)

Si potrebbe anche convertire il byte [] in una stringa di 'sicuro' usando Base32 o Base64, ad esempio:

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

naturalmente ci sono molte varianti di cui sopra, come:

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

Ecco una soluzione utilizza TreeMap, interfaccia comparatore e java.util.Arrays.equals metodo Java (byte [], byte []);

NOTA: L'ordinamento nella mappa non è rilevante con questo metodo

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;
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top