我使用布尔数组作为HashMap的键。但问题是当一个不同的数组作为键传递时,HashMap无法获取键,尽管元素是相同的。 (因为它们是不同的对象)。
如何使用数组作为键? 这是代码:
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");
}
}
数组a
和t
都包含相同的元素,但HashMap不会为t
返回任何内容。
如何让它发挥作用?
答案 0 :(得分:23)
你不能这样做。 t
和a
都会有不同的hashCode()
值,因为java.lang.Array.hashCode()
方法是从Object
继承的,t
使用引用来计算哈希码(默认实现)。因此,数组的哈希码是依赖于引用的,这意味着您将获得a
和equals
的不同哈希码值。此外,boolean
不适用于两个数组,因为它也基于引用。
您可以这样做的唯一方法是创建一个自定义类,将equals
数组保留为内部成员。然后,您需要覆盖hashCode
和List<Boolean>
,以确保包含具有相同值的数组的实例相等并且具有相同的哈希代码。
更简单的选择可能是使用hashCode()
作为密钥。根据{{3}},List
的{{1}}实现定义为:
int hashCode = 1;
Iterator<E> i = list.iterator();
while (i.hasNext()) {
E obj = i.next();
hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode());
}
正如您所看到的,它取决于列表中的值而不是引用,因此这应该适合您。
答案 1 :(得分:8)
不可能对数组执行此操作,因为任何两个不同的数组都不会比较equals
,即使它们具有相同的元素。
您需要从容器类映射,例如ArrayList<Boolean>
(或简称为List<Boolean>
。或许BitSet
更合适。
答案 2 :(得分:4)
Map
实现依赖于密钥的equals
和hashCode
方法。 java中的数组直接来自Object
,它们使用equals
的{{1}}和hashCode
Object
,只比较identity
。
如果我是你,我会创建一个班级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;
}
}
之后,您可以将密钥用于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
答案 3 :(得分:1)
boolean[] t;
t = a;
如果您这样做,而不是boolean[] t = {false, false};
,那么您将获得所需的输出。
这是因为Map
将reference
存储为key
,而在您的情况下,尽管t
具有相同的值,但它不具有相同的值引用为a
。
因此,当您提供t=a
时,它会起作用。
与此非常相似: -
String a = "ab";
String b = new String("ab");
System.out.println(a==b); // This will give false.
a
&amp; b
保持相同的值,但具有不同的引用。因此,当您尝试使用==
比较引用时,它会提供false
。
但如果您提供a = b;
,然后尝试比较reference
,则会获得true
。
答案 4 :(得分:1)
可能是因为Array返回的equals()方法与你期望的不同。您应该考虑实现自己的收集和覆盖equals()和hashCode()。
答案 5 :(得分:1)
地图使用equals()
来测试您的密钥是否相同。
Object
测试==
中该方法的默认实现,即引用相等。因此,由于您的两个数组不是同一个数组,equals
总是返回false。
您需要在两个数组上调用映射Arrays.equals
以检查是否相等。
您可以创建一个使用Arrays.equals
的数组包装器类,然后按预期工作:
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})));
}
答案 6 :(得分:1)
您可以创建一个包含该数组的类。根据值实现该类的hashCode()和equals()方法:
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;
}
}
然后您可以使用:
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);
答案 7 :(得分:0)
您可以使用接受外部散列和比较策略的库(宝库)。
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());
答案 8 :(得分:0)
这适用于任何类型的数组:
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);
}
}
以下是转换为使用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)));
我使用的是Java 8,但我认为Java 7拥有您需要的一切。我测试了hashCode并使用TestUtils等于。
另一个想法是Joshua Bloch的第25项:&#34;首选列表到阵列。&#34;