Frage

Sehen Sie irgendein Problem mit einem Byte-Array als Map-Taste? Ich könnte auch new String(byte[]) und Hash von String tun, aber es ist einfacher byte[] zu verwenden.

War es hilfreich?

Lösung

Das Problem ist, dass byte[] verwendet Objektidentität für equals und hashCode, so dass

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

wird nicht in einem HashMap entsprechen. Ich sehe drei Möglichkeiten:

  1. Wrapping in einem String, aber dann müssen Sie kodieren Fragen vorsichtig sein (Sie sicher vornehmen müssen, dass die Byte -> String -> Byte Ihnen das gleiche Bytes gibt).
  2. Verwenden Sie List<Byte> (kann im Speicher teuer sein).
  3. Machen Sie Ihre eigene Verpackung Klasse, schreibt hashCode und equals den Inhalt der Byte-Arrays zu verwenden.

Andere Tipps

Es ist in Ordnung, solange Sie nur Referenz Gleichheit für Ihren Schlüssel wollen - Arrays nicht implementieren „Wertgleichheit“ in der Art und Weise, die Sie würden wahrscheinlich wollen. Zum Beispiel:

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

druckt etwas wie:

false
1671711
11394033

(Die tatsächlichen Zahlen sind irrelevant, die Tatsache, dass sie anders sind, ist wichtig.)

Angenommen, Sie wirklich wollen Gleichheit, empfehle ich Ihnen Ihre eigenen Wrapper erstellen, die eine byte[] enthält und implementiert Gleichheit und Hash-Code-Generierung in geeigneter Weise:

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

Beachten Sie, dass, wenn Sie die Werte innerhalb des Byte-Array ändern, nachdem die ByteArrayWrapper Verwendung als Schlüssel in einer HashMap (etc) Sie werden Probleme haben, wieder den Schlüssel aufzuzublicken ... Sie eine Kopie der Daten übernehmen könnten in der ByteArrayWrapper Konstruktor, wenn Sie wollen, aber offensichtlich wird, dass eine Verschwendung von Leistung, wenn Sie wissen, dass Sie nicht den Inhalt des Byte-Arrays werden zu ändern.

EDIT: Wie in den Kommentaren erwähnt, können Sie auch ByteBuffer für diese (insbesondere verwenden könnte, seine ByteBuffer#wrap(byte[]) Methode). Ich weiß nicht, ob es wirklich das Richtige, da alle zusätzlichen Fähigkeiten, die ByteBuffers haben, die Sie nicht brauchen, aber es ist eine Option.

Wir verwenden ByteBuffer für diese (Dies ist im Grunde die byte [] Wrapper mit einem Komparator)

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

druckt

true

Sie könnten java.math.BigInteger verwenden. Es hat einen BigInteger(byte[] val) Konstruktor. Es ist ein Referenztyp, so kann als Schlüssel für Hash-Tabelle verwendet werden. Und .equals() und .hashCode() sind als für entsprechende ganze Zahlen definiert, was bedeutet, BigInteger konsistent hat Semantik als byte [] Array entspricht.

Ich bin sehr überrascht, dass die Antworten nicht die einfachste Alternative Hinweis darauf sind.

Ja, ist es nicht möglich, eine HashMap zu verwenden, aber niemand verhindert, dass Sie eine SortedMap als Alternative verwenden. Die einzige Sache ist, einen Komparator zu schreiben, die die Arrays vergleichen muss. Es ist nicht so performant wie eine HashMap, aber wenn Sie eine einfache Alternative wollen, hier gehen Sie (Sie können SortedMap mit Karte ersetzen, wenn Sie die Implementierung ausblenden möchten):

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

Diese Implementierung kann für andere Arrays eingestellt werden, das einzige, was Sie beachten müssen, ist, dass gleich Arrays (= gleiche Länge mit dem gleichen Mitgliedern) müssen 0 zurückgeben und Sie haben eine determistic Ordnung

Ich glaube, dass Arrays in Java nicht unbedingt die hashCode() und equals(Object) Methoden intuitiv umzusetzen. Das heißt, zwei identische Byte-Arrays nicht notwendigerweise den gleichen Hash-Code teilen, und sie werden nicht notwendigerweise Anspruch gleich sind. Ohne diese beiden Züge, Ihre HashMap wird unerwartet verhalten.

Daher empfehle ich gegen mit byte[] als Schlüssel in einer HashMap.

sollten Sie verwenden eine Klasse somthing wie ByteArrKey und Überlastung hashcode und gleiche Methoden erstellen, denken Sie daran, den Vertrag zwischen ihnen.

Dies gibt Ihnen mehr Flexibilität, wie Sie 0 Einträge überspringen können, die am Ende des Byte-Array angehängt werden, besonders, wenn Sie nur einen Teil Form der anderen Bytepuffer kopieren.

So können Sie entscheiden, wie beiden Objekte gleich sein sollten.

Ich sehe Probleme, da Sie Arrays.equals und Array.hashCode, anstelle von Standard-Array-Implementierungen verwenden sollten

Arrays.toString (Byte)

Sie können auch die byte [] zu einem 'sicheren' String mit Base32 oder Base64, zum Beispiel konvertieren:

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

Natürlich gibt es viele Varianten der oben genannten, wie:

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

Hier ist eine Lösung unter Verwendung von TreeMap, Komparator Schnittstelle und Java-Methode java.util.Arrays.equals (byte [], byte []);

Hinweis: Die Reihenfolge in der Karte ist nicht relevant, mit dieser Methode

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;
    }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top