J'utilise des tableaux booléens comme clés d'un HashMap. Mais le problème est que HashMap ne parvient pas à obtenir les clés lorsqu'un tableau différent est passé en tant que clé, bien que les éléments soient les mêmes. (Comme ce sont des objets différents).
Comment puis-je le faire fonctionner avec des tableaux comme des clés? Voici le code:
public class main {
public static HashMap<boolean[], Integer> h;
public static void main(String[] args){
boolean[] a = {false, false};
h = new HashMap<boolean[], Integer>();
h.put(a, 1);
if(h.containsKey(a)) System.out.println("Found a");
boolean[] t = {false, false};
if(h.containsKey(t)) System.out.println("Found t");
else System.out.println("Couldn't find t");
}
}
Les tableaux a
et t
contiennent les mêmes éléments, mais HashMap ne renvoie rien pour t
.
Comment puis-je le faire fonctionner?
Vous ne pouvez pas le faire de cette façon. t
et a
auront des valeurs hashCode()
différentes, car la méthode Java.lang.Array.hashCode()
est héritée de Object
, qui utilise la référence pour calculer le code de hachage (implémentation par défaut). Par conséquent, le code de hachage pour les tableaux dépend de la référence, ce qui signifie que vous obtiendrez une valeur de code de hachage différente pour t
et a
. De plus, equals
ne fonctionnera pas pour les deux tableaux, car il est également basé sur la référence.
La seule façon de procéder consiste à créer une classe personnalisée qui conserve le tableau boolean
en tant que membre interne. Vous devez ensuite redéfinir equals
et hashCode
de manière à ce que les instances contenant des tableaux avec des valeurs identiques soient égales et possèdent le même code de hachage.
Une option plus simple pourrait être d'utiliser List<Boolean>
comme clé. Selon la documentation l'implémentation hashCode()
pour List
est définie comme suit:
int hashCode = 1;
Iterator<E> i = list.iterator();
while (i.hasNext()) {
E obj = i.next();
hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode());
}
Comme vous pouvez le constater, cela dépend des valeurs de votre liste et non de la référence. Cela devrait donc fonctionner pour vous.
Cela n'est pas possible avec les tableaux, car deux tableaux différents ne comparent pas equals
, même s'ils ont les mêmes éléments.
Vous devez mapper à partir de la classe conteneur, par exemple ArrayList<Boolean>
(ou simplement List<Boolean>
. Peut-être que BitSet
serait encore plus approprié.
Les implémentations Map
reposent sur les méthodes equals
et hashCode
de la clé. Les tableaux en Java sont directement étendus à partir de Object
, ils utilisent les valeurs par défaut equals
et hashCode
de Object
qui ne compare que identity
.
Si j'étais vous, je créerais une classe Key
class Key {
private final boolean flag1;
private final boolean flag2;
public Key(boolean flag1, boolean flag2) {
this.flag1 = flag1;
this.flag2 = flag2;
}
@Override
public boolean equals(Object object) {
if (!(object instanceof Key)) {
return false;
}
Key otherKey = (Key) object;
return this.flag1 == otherKey.flag1 && this.flag2 == otherKey.flag2;
}
@Override
public int hashCode() {
int result = 17; // any prime number
result = 31 * result + Boolean.valueOf(this.flag1).hashCode();
result = 31 * result + Boolean.valueOf(this.flag2).hashCode();
return result;
}
}
Après cela, vous pouvez utiliser votre clé avec Map
:
Map<Key, Integer> map = new HashMap<>();
Key firstKey = new Key(false, false);
map.put(firstKey, 1);
Key secondKey = new Key(false, false) // same key, different instance
int result = map.get(secondKey); // --> result will be 1
Référence: Code de hachage Java d'un champ
boolean[] t;
t = a;
Si vous donnez ceci, au lieu de boolean[] t = {false, false};
, vous obtiendrez le résultat souhaité.
En effet, Map
stocke reference
en tant que key
et, dans votre cas, même si t
a les mêmes valeurs, il n'a pas la même référence que a
.
Par conséquent, lorsque vous donnez t=a
, cela fonctionnera.
C'est très semblable à ceci: -
String a = "ab";
String b = new String("ab");
System.out.println(a==b); // This will give false.
a
& b
ont la même valeur, mais ont des références différentes. Par conséquent, lorsque vous essayez de comparer la référence en utilisant ==
, il donne false
.
Mais si vous donnez a = b;
puis essayez de comparer reference
, vous obtiendrez true
.
Vous pouvez créer une classe contenant le tableau. Implémente les méthodes hashCode () et equals () pour cette classe, en fonction de valeurs:
public class boolarray {
boolean array[];
public boolarray( boolean b[] ) {
array = b;
}
public int hashCode() {
int hash = 0;
for (int i = 0; i < array.length; i++)
if (array[i])
hash += Math.pow(2, i);
return hash;
}
public boolean equals( Object b ) {
if (!(b instanceof boolarray))
return false;
if ( array.length != ((boolarray)b).array.length )
return false;
for (int i = 0; i < array.length; i++ )
if (array[i] != ((boolarray)b).array[i])
return false;
return true;
}
}
Vous pouvez ensuite utiliser:
boolarray a = new boolarray( new boolean[]{ true, true } );
boolarray b = new boolarray( new boolean[]{ true, true } );
HashMap<boolarray, Integer> map = new HashMap<boolarray, Integer>();
map.put(a, 2);
int c = map.get(b);
System.out.println(c);
C’est probablement parce que la méthode equals () pour les retours sur les tableaux est différente de celle que vous attendez. Vous devriez penser à mettre en œuvre votre propre collecte et surcharger equals () et hashCode ().
Map utilise equals()
pour vérifier si vos clés sont identiques.
L'implémentation par défaut de cette méthode dans Object
teste ==
, c'est-à-dire une égalité de référence. Donc, comme vos deux tableaux ne sont pas identiques, equals
renvoie toujours false.
Pour vérifier l’égalité, vous devez appeler le mappage Arrays.equals
sur les deux tableaux.
Vous pouvez créer une classe wrapper de tableau qui utilise Arrays.equals
et cela fonctionnera comme prévu:
public static final class ArrayHolder<T> {
private final T[] t;
public ArrayHolder(T[] t) {
this.t = t;
}
@Override
public int hashCode() {
int hash = 7;
hash = 23 * hash + Arrays.hashCode(this.t);
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final ArrayHolder<T> other = (ArrayHolder<T>) obj;
if (!Arrays.equals(this.t, other.t)) {
return false;
}
return true;
}
}
public static void main(String[] args) {
final Map<ArrayHolder<Boolean>, Integer> myMap = new HashMap<>();
myMap.put(new ArrayHolder<>(new Boolean[]{true, true}), 7);
System.out.println(myMap.get(new ArrayHolder<>(new Boolean[]{true, true})));
}
Cela devrait fonctionner pour les tableaux de tout type:
class ArrayHolder<T> {
private final T[] array;
@SafeVarargs
ArrayHolder(T... ts) { array = ts; }
@Override public int hashCode() { return Arrays.hashCode(array); }
@Override public boolean equals(Object other) {
if (array == other) { return true; }
if (! (other instanceof ArrayHolder) ) {
return false;
}
//noinspection unchecked
return Arrays.equals(array, ((ArrayHolder) other).array);
}
}
Voici votre exemple spécifique converti pour utiliser ArrayHolder:
// boolean[] a = {false, false};
ArrayHolder<Boolean> a = new ArrayHolder<>(false, false);
// h = new HashMap<boolean[], Integer>();
Map<ArrayHolder<Boolean>, Integer> h = new HashMap<>();
h.put(a, 1);
// if(h.containsKey(a)) System.out.println("Found a");
assertTrue(h.containsKey(a));
// boolean[] t = {false, false};
ArrayHolder<Boolean> t = new ArrayHolder<>(false, false);
// if(h.containsKey(t)) System.out.println("Found t");
assertTrue(h.containsKey(t));
assertFalse(h.containsKey(new ArrayHolder<>(true, false)));
J'ai utilisé Java 8, mais je pense que Java 7 a tout ce dont vous avez besoin pour cela. J'ai testé hashCode et égal à l'aide de TestUtils .
Une autre pensée est celle de l’article 25 de Joshua Bloch: "Préférez les listes aux tableaux".
Vous pouvez utiliser une bibliothèque qui accepte une stratégie de hachage et de comparaison externe (outil).
class MyHashingStrategy implements HashingStrategy<boolean[]> {
@Override
public int computeHashCode(boolean[] pTableau) {
return Arrays.hashCode(pTableau);
}
@Override
public boolean equals(boolean[] o1, boolean[] o2) {
return Arrays.equals(o1, o2);
}
}
Map<boolean[], T> map = new TCustomHashMap<boolean[],T>(new MyHashingStrategy());