En regardant Les clés de la carte ne sont pas bonnes si elles sont arrangées, il existe différentes manières de le faire fonctionner en pensant que cela ne fonctionnera pas. Notes sur l'utilisation d'un tableau d'octets comme clé dans Java Map est lié, et [Utilisation d'un tableau d'octets comme clé de mappage](http: / Il y a un lien sur /stackoverflow.com/questions/1058149/using-a-byte-array-as-map-key), et il y a diverses choses écrites dans le dernier Stack Overflow.
Ici, c'est HashMap. Cela devrait changer avec TreeMap. → Comment utiliser un tableau pour la clé TreeMap L'hypothèse clé est
Le premier et le second s'utilisent parfaitement avec containsKey, get, put de HashMap. Le troisième n'est pas imuutable et peut être modifié ultérieurement, mais si vous modifiez la valeur de clé après l'avoir placée, il se peut qu'il ne soit pas trouvé. Si vous changez cela en DEF après l'avoir mis dans ABC, il est naturel que vous ne puissiez pas le trouver dans ABC, mais il est possible qu'il ne soit pas trouvé dans DEF. La raison en est que le hashCode change, mais ce qui se trouve à l'origine à l'endroit qui correspond au hashCode de DEF est entré à l'endroit qui correspond au hashCode de ABC.
Equals et hashCode sont incorrects pour les tableaux.
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);
}
Le résultat est ···
false
false
false
true
true
La raison pour laquelle Arrays.equals et Arrays.hashCode sont dérangés est que les equals et hashCode du tableau sont incorrects.
Comment implémenter equals et hashCode en enveloppant l'octet [].
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);
}
}
Testons-le.
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));
}
Le résultat est ···
false
true
true
OK
OK
C'est naturel car nous appelons Arrays.equals et Arrays.hashCode.
(1/17 postscript) Si vous l'apportez de Stack Overflow, c'est inutile. Puisqu'il ne contient que le tableau tel quel, il ne fonctionnera pas correctement si le tableau passé au constructeur est modifié. C'est un gros problème, alors essayons-le.
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);
}
Quand tu cours ...
OK
null
null
null
{ByteArrayWrapper@9669=OK}
Les données sont dans la carte, mais je ne peux pas les obtenir avec la clé. Pour éviter cela, faites une copie du tableau dans le constructeur.
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);
}
}
Si vous exécutez le même programme de test ...
OK
OK
OK
null
{ByteArrayWrapper@7861=OK}
La disposition à l'intérieur est protégée.
Il y a un commentaire que vous pouvez utiliser avec java.nio.ByteBuffer sans créer de classe wrapper. Testons-le.
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));
}
Le résultat est ···
false
true
true
OK
OK
OK du tout. C'est la meilleure sensation. J'aime la bibliothèque standard ajoutée à partir de JDK 1.4.
Il y a un commentaire que java.math.BigInteger ne peut pas aller car le constructeur reçoit l'octet []. Cependant, quand ce sera {0, 100}, ce sera avec {100}, non? Il y a un retour de commentaire. Testons-le.
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));
}
Le résultat est ···
false
false
true
true
true
true
OK
OK
OK
C'est dommage. {0, 100} et {100} sont ensemble. C'est dangereux si vous l'utilisez sans le savoir.
String s01 = new String (b01, "UTF-8"); Il semble que les caractères soient déformés. String s02 = Arrays.toString (b01); serait légitime, mais la chaîne de sortie serait "[1, 2, 3]". Je n'ai pas besoin de parenthèses ou de blancs. Par conséquent, créez une méthode utilitaire qui génère des valeurs numériques, des valeurs numériques, ... Convertissez le nombre en hexadécimal. Convertissez le nombre en 36 base. (Caractère.MAX_RADIX == 36) encodage base64.
Cependant, il est inefficace car la taille est nettement plus grande que l'octet [].
Je pense que ByteBuffer est bien, mais si vous voulez utiliser int [] au lieu de byte [], il y a IntBuffer. Ou plutôt, tous les types primitifs sont disponibles. Divers en quelque sorte Buffer. Je ne savais pas ça.
Strictement pas imuutable, mais vous ne l'ajouteriez pas avec put après l'avoir spécifié comme clé. (1/17 postscript) En regardant le javadoc et la source de ByteBuffer, get () est également inutile. Cela est dû au fait que la position actuelle se déplace et est égale et que hashCode cible la position actuelle et au-delà. Equals et hashCode sont accessibles par get (int). Les notes suivantes sont écrites en ByteBuffer / hashCode.
Le code de hachage du tampon dépend du contenu. Évitez d'utiliser le tampon comme clé pour les cartes de hachage ou d'autres structures de données à moins qu'il ne soit clair que le contenu du tampon ne changera pas à l'avenir.
Mais si vous ne savez pas comment l'utiliser à l'extérieur, vous pouvez être assuré que vous ne pouvez pas le changer en créant ByteArrayWrapper de la manière habituelle. (1/17 postscript) Je suis désolé, le premier ByteArray Wrapper que j'ai sorti n'était pas imuutable. Fixé.
(1/18 postscript) Je l'ai mis à la fin de TreeMap, mais c'est un wrapper qui peut être utilisé pour les deux. Modifié à partir de la source dans HashMap: Modification de l'argument du constructeur d'octet [] en octet ..., ajout d'égaux (octet [] autre), ajout de compareTo ()
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