如何使HashMap与数组一起使用?

时间:2013-03-22 17:02:20

标签: java arrays hashmap

我使用布尔数组作为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");

}

}

数组at都包含相同的元素,但HashMap不会为t返回任何内容。

如何让它发挥作用?

9 个答案:

答案 0 :(得分:23)

你不能这样做。 ta都会有不同的hashCode()值,因为java.lang.Array.hashCode()方法是从Object继承的,t使用引用来计算哈希码(默认实现)。因此,数组的哈希码是依赖于引用的,这意味着您将获得aequals的不同哈希码值。此外,boolean不适用于两个数组,因为它也基于引用。

您可以这样做的唯一方法是创建一个自定义类,将equals数组保留为内部成员。然后,您需要覆盖hashCodeList<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实现依赖于密钥的equalshashCode方法。 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

参考: Java hash code from one field

答案 3 :(得分:1)

boolean[] t;
t = a;

如果您这样做,而不是boolean[] t = {false, false};,那么您将获得所需的输出。

这是因为Mapreference存储为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;