Java使用byte []作为地图中的键

时间:2018-07-25 11:44:00

标签: java dictionary hashmap treemap comparable

我在Java映射方面有些挣扎。 我想要一个以byte []作为键并返回自定义对象作为值的映射。

首先,我尝试使用哈希映射,但是因为我曾经使用过不同的数组,但是具有相同的值,所以它不起作用。同样不可能使用Arrays.hashCode(),因为具有不同值的多重数组将具有相同的哈希值。

现在我正在使用TreeMap而不是HashMap进行尝试,但是现在我不知道如何解决

Exception in thread "main" java.lang.ClassCastException: [B cannot be cast to java.lang.Comparable
    at java.util.TreeMap.compare(TreeMap.java:1294)
    at java.util.TreeMap.put(TreeMap.java:538)

当我尝试添加对象时引发的异常。

有人知道如何解决此异常吗? 或更具体地讲,我应该如何以及向树图提供哪个比较器?

2 个答案:

答案 0 :(得分:4)

好,在这里介绍Java。

有两件事在起作用:

  1. 数组是基于身份的,而不是基于值的(有关更多详细信息,请参见this answer;尽管如此,我找不到任何正式的规范)。

因此,以下内容将返回false

byte[] a = {1};
byte[] b = {1};
System.out.println(a.equals(b));
  1. 数组未实现Comparable(对它们而言没有意义)。为了将任何内容放入TreeMap,您必须为其提供Comparator(使用this constructor),或者必须实现Comparable

EDIT :如果您确实有一些要用作键的二进制数据(这很奇怪),您可以:

  1. 使用Java NIO的ByteBuffer及其ByteBuffer.wrap(byte[])方法(缺点:此类是可变的,但您的原始版本中的byte[]也是如此)。

  2. byte[]上创建一个自定义(最好是不可变的)包装器,并将该类用作HashMap / TreeMap的键(尽管,如果不需要排序, ,出于性能原因,请勿使用TreeMap

示例自定义包装的存根:

final class ByteWrapper {

    private final byte[] bytes;

    public ByteWrapper(byte[] bytes) {
        this.bytes = bytes;
    }

    @Override
    public boolean equals(Object o) {
        // type checks here
        ByteWrapper that = (ByteWrapper) o;
        return Arrays.equals(bytes, that.bytes);
    }

    @Override
    public int hashCode() {
        return Arrays.hashCode(bytes);
    }
}

答案 1 :(得分:2)

原因是您的密钥未实现Comparable

一种解决方案是创建一个类(包装器)用作键:

class ByteArrayKey implements Comparable{
    byte[] value;

    ...
}

您所要做的就是根据需要实现compareTo(T o )(选中Arrays),当然可以正确使用此实例。

此方法的优点在于,您不必在要使用构造函数实例化的每个TreeMap中设置Comparator

public TreeMap(Comparator<? super K> comparator)

提供更简洁,可维护的代码(如果相等性更改,则只需更改一次)。