Wenn Sie sich Kartenschlüssel sind nicht gut, wenn sie angeordnet sind ansehen, gibt es verschiedene Möglichkeiten, damit es funktioniert, während Sie denken, dass es nicht funktioniert. Hinweise zur Verwendung des Byte-Arrays als Schlüssel in Java Map ist verknüpft und [Verwendung eines Byte-Arrays als Map-Schlüssel](http: / Es gibt einen Link unter /stackoverflow.com/questions/1058149/using-a-byte-array-as-map-key), und im letzten Stapelüberlauf sind verschiedene Dinge geschrieben.
Hier ist es HashMap. Dies sollte sich mit TreeMap ändern. → So verwenden Sie ein Array für den TreeMap-Schlüssel Die Hauptannahme ist --Implementieren gleich
Der erste und der zweite werden perfekt mit includesKey, get, put von HashMap verwendet. Der dritte ist nicht unveränderlich und kann später geändert werden. Wenn Sie jedoch den Schlüsselwert nach dem Einfügen ändern, wird er möglicherweise nicht gefunden. Wenn Sie dies nach dem Einfügen in ABC in DEF ändern, können Sie es natürlich nicht in ABC finden, aber es besteht die Möglichkeit, dass es in DEF nicht gefunden wird. Der Grund ist, dass sich der Hashcode ändert, aber was ursprünglich an die Stelle geht, die dem Hashcode von DEF entspricht, hat die Stelle eingegeben, die dem Hashcode von ABC entspricht.
Equals und hashCode sind für Arrays falsch.
Main.java
public static void main(String[] args) {
byte[] b01 = { 1, 2, 3 };
byte[] b02 = { 1, 2, 3 };
int h01 = b01.hashCode();
int h02 = b02.hashCode();
System.out.println(b01 == b02);
System.out.println(b01.equals(b02));
System.out.println(h01 == h02);
int h11 = Arrays.hashCode(b01);
int h12 = Arrays.hashCode(b02);
System.out.println(Arrays.equals(b01, b02));
System.out.println(h11 == h12);
}
Ergebnis ist ···
false
false
false
true
true
Der Grund, warum Arrays.equals und Arrays.hashCode gestört werden, ist, dass Equals und HashCode des Arrays falsch sind.
So implementieren Sie equals und hashCode durch Umbrechen von byte [].
ByteArrayWrapper.java
import java.util.Arrays;
public class ByteArrayWrapper {
private byte[] data;
public ByteArrayWrapper(byte[] data) {
this.data = data;
}
public boolean equals(Object other) {
if (other instanceof ByteArrayWrapper) {
return Arrays.equals(data, ((ByteArrayWrapper) other).data);
}
return false;
}
public int hashCode() {
return Arrays.hashCode(data);
}
}
Lass es uns testen.
Main.java
public static void main(String[] args) {
byte[] b01 = { 1, 2, 3 };
byte[] b02 = { 1, 2, 3 };
ByteArrayWrapper w01 = new ByteArrayWrapper(b01);
ByteArrayWrapper w02 = new ByteArrayWrapper(b02);
Map<ByteArrayWrapper, String> map = new HashMap<>();
map.put(w01, "OK");
int h01 = w01.hashCode();
int h02 = w02.hashCode();
System.out.println(w01 == w02);
System.out.println(w01.equals(w02));
System.out.println(h01 == h02);
System.out.println(map.get(w01));
System.out.println(map.get(w02));
}
Ergebnis ist ···
false
true
true
OK
OK
Es ist natürlich, weil wir Arrays.equals und Arrays.hashCode aufrufen.
(1/17 Nachschrift) Wenn Sie es von Stack Overflow bringen, ist es nutzlos. Da das Array nur so bleibt, wie es ist, tritt eine Fehlfunktion auf, wenn das an den Konstruktor übergebene Array geändert wird. Es ist eine große Sache, also lass es uns versuchen.
Main.java
public static void main(String[] args) {
byte[] b01 = { 1, 2, 3 };
byte[] b02 = { 1, 2, 3 };
byte[] b03 = { 9, 2, 3 };
ByteArrayWrapper w01 = new ByteArrayWrapper(b01);
ByteArrayWrapper w02 = new ByteArrayWrapper(b02);
ByteArrayWrapper w03 = new ByteArrayWrapper(b03);
Map<ByteArrayWrapper, String> map = new HashMap<>();
map.put(w01, "OK");
System.out.println(map.get(w01));
b01[0] = 9;
System.out.println(map.get(w01));
System.out.println(map.get(w02));
System.out.println(map.get(w03));
System.out.println(map);
}
Wenn du rennst ...
OK
null
null
null
{ByteArrayWrapper@9669=OK}
Die Daten befinden sich in der Karte, aber ich kann sie nicht mit dem Schlüssel erhalten. Um dies zu verhindern, erstellen Sie eine Kopie des Arrays im Konstruktor.
ByteArrayWrapper.java
import java.util.Arrays;
public class ByteArrayWrapper {
private byte[] data;
public ByteArrayWrapper(byte[] data) {
this.data = data.clone();
}
public boolean equals(Object other) {
if (other instanceof ByteArrayWrapper) {
return Arrays.equals(data, ((ByteArrayWrapper) other).data);
}
return false;
}
public int hashCode() {
return Arrays.hashCode(data);
}
}
Wenn Sie das gleiche Testprogramm ausführen ...
OK
OK
OK
null
{ByteArrayWrapper@7861=OK}
Die Anordnung im Inneren ist geschützt.
Es gibt einen Kommentar, den Sie mit java.nio.ByteBuffer verwenden können, ohne eine Wrapper-Klasse zu erstellen. Lass es uns testen.
Main.java
public static void main(String[] args) {
byte[] b01 = { 1, 2, 3 };
byte[] b02 = { 1, 2, 3 };
ByteBuffer w01 = ByteBuffer.wrap(b01);
ByteBuffer w02 = ByteBuffer.wrap(b02);
Map<ByteBuffer, String> map = new HashMap<>();
map.put(w01, "OK");
int h01 = w01.hashCode();
int h02 = w02.hashCode();
System.out.println(w01 == w02);
System.out.println(w01.equals(w02));
System.out.println(h01 == h02);
System.out.println(map.get(w01));
System.out.println(map.get(w02));
}
Ergebnis ist ···
false
true
true
OK
OK
OK überhaupt. Das ist das beste Gefühl. Ich mag die Standardbibliothek, die aus JDK 1.4 hinzugefügt wurde.
Es gibt einen Kommentar, den java.math.BigInteger nicht ausführen kann, da der Konstruktor Byte [] empfängt. Wenn es jedoch {0, 100} ist, wird es mit {100} sein, richtig? Es gibt eine Kommentarrückgabe. Lass es uns testen.
Main.java
public static void main(String[] args) {
byte[] b01 = { 0, 100 };
byte[] b02 = { 0, 100 };
byte[] b03 = { 100 };
BigInteger w01 = new BigInteger(b01);
BigInteger w02 = new BigInteger(b02);
BigInteger w03 = new BigInteger(b03);
Map<BigInteger, String> map = new HashMap<>();
map.put(w01, "OK");
int h01 = w01.hashCode();
int h02 = w02.hashCode();
int h03 = w03.hashCode();
System.out.println(w01 == w02);
System.out.println(w01 == w03);
System.out.println(w01.equals(w02));
System.out.println(w01.equals(w03));
System.out.println(h01 == h02);
System.out.println(h01 == h03);
System.out.println(map.get(w01));
System.out.println(map.get(w02));
System.out.println(map.get(w03));
}
Ergebnis ist ···
false
false
true
true
true
true
OK
OK
OK
Das ist sehr schade. {0, 100} und {100} sind zusammen. Es ist gefährlich, wenn Sie es verwenden, ohne es zu wissen.
String s01 = neuer String (b01, "UTF-8"); Es scheint, dass die Zeichen verstümmelt sind. String s02 = Arrays.toString (b01); wäre legitim, aber der Ausgabe-String wäre "[1, 2, 3]". Ich brauche keine Klammern oder Leerzeichen. Erstellen Sie daher eine Dienstprogrammmethode, die numerische Werte, numerische Werte usw. ausgibt. Konvertieren Sie die Zahl in hexadezimal. Konvertieren Sie die Zahl in 36 Basis. (Character.MAX_RADIX == 36) base64 codieren.
Es ist jedoch ineffizient, da die Größe definitiv größer als Byte ist [].
Ich denke, ByteBuffer ist in Ordnung, aber wenn Sie int [] anstelle von Byte [] verwenden möchten, gibt es IntBuffer. Oder besser gesagt, alle primitiven Typen sind verfügbar. Verschiedene irgendwie Puffer. Das wusste ich nicht.
Genau genommen ist es nicht unveränderlich, aber Sie werden es nicht mit put hinzufügen, nachdem Sie es als Schlüssel angegeben haben. (1/17 postscript) Wenn man sich das Javadoc und die Quelle von ByteBuffer ansieht, ist get () ebenfalls nutzlos. Dies liegt daran, dass sich die aktuelle Position bewegt und gleich ist und hashCode auf die aktuelle Position und darüber hinaus abzielt. Auf Equals und HashCode wird mit get (int) zugegriffen. Die folgenden Hinweise sind in ByteBuffer / hashCode geschrieben.
Der Hash-Code des Puffers ist inhaltsabhängig. Vermeiden Sie es, den Puffer als Schlüssel für Hash-Maps oder andere Datenstrukturen zu verwenden, es sei denn, es ist klar, dass sich der Inhalt des Puffers in Zukunft nicht ändern wird.
Wenn Sie jedoch nicht wissen, wie Sie es im Freien verwenden sollen, können Sie sicher sein, dass Sie es nicht ändern können, indem Sie ByteArrayWrapper auf die übliche Weise erstellen. (1/17 Nachtrag) Es tut mir leid, der erste ByteArray Wrapper, den ich herausbrachte, war nicht unveränderlich. Fest.
(1/18 Nachschrift) Ich habe es am Ende von TreeMap eingefügt, aber es ist ein Wrapper, der für beide verwendet werden kann. Geändert von der Quelle in HashMap: Das Konstruktorargument wurde von Byte [] in Byte ... geändert, gleich (Byte [] andere) hinzugefügt, compareTo () hinzugefügt
ByteArrayWrapper.java
import java.util.Arrays;
public class ByteArrayWrapper implements Comparable<ByteArrayWrapper> {
private byte[] data;
public ByteArrayWrapper(byte... data) {
this.data = data.clone();
}
public boolean equals(Object other) {
if (other instanceof ByteArrayWrapper) {
return equals(((ByteArrayWrapper) other).data);
}
return false;
}
public boolean equals(byte[] other) {
return Arrays.equals(data, other);
}
public int hashCode() {
return Arrays.hashCode(data);
}
public int compareTo(ByteArrayWrapper that) {
int n = Math.min(this.data.length, that.data.length);
for (int i = 0; i < n; i++) {
int cmp = Byte.compare(this.data[i], that.data[i]);
if (cmp != 0)
return cmp;
}
return this.data.length - that.data.length;
}
}
Recommended Posts