Java 使用 byte[] 作为 Map 中的键
Java use byte[] as key in a Map
我在使用 Java 地图时遇到了一些困难。
我想要一个以 byte[] 作为键和 returns 自定义对象作为值的映射。
首先我尝试使用哈希映射,但因为我习惯于使用不同的数组,但具有相同的值,所以它不起作用。同样使用 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)
当我尝试添加对象时抛出异常。
有人知道如何解决这个异常吗?
或者更具体地说,我应该如何以及向 TreeMap 提供哪个比较器?
好的,这里介绍 material 到 Java。
有两件事在起作用:
- 数组是基于身份的,而不是基于值的(有关更多详细信息,请参阅 this answer;不过,我找不到任何正式的规范)。
因此,以下returns false
:
byte[] a = {1};
byte[] b = {1};
System.out.println(a.equals(b));
- 数组未实现
Comparable
(it would make no sense for them). In order to put anything into a TreeMap
, you must either provide a Comparator
for it (using this constructor), or it must implement Comparable
。
编辑:如果你确实有一些二进制数据想用作键(这是一个相当奇怪的情况),你可以:
使用 Java NIO 的 ByteBuffer
and its ByteBuffer.wrap(byte[])
方法(缺点:此 class 是可变的,但在您的原始版本中 byte[]
也是可变的)。
在 byte[]
上创建自定义(最好是不可变的)包装器,并将此 class 用作 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);
}
}
原因是您的密钥没有实现Comparable
。
一个解决方案是创建一个 class(包装器)用作密钥:
class ByteArrayKey implements Comparable{
byte[] value;
...
}
您所要做的就是根据需要实施 compareTo(T o )
(检查 Arrays
),当然还要正确使用此实例。
这背后的优点是您不必在每个 TreeMap
中设置一个 Comparator
,您将使用构造函数实例化:
public TreeMap(Comparator<? super K> comparator)
提供更加简洁和可维护的代码(如果等式发生变化,您只需更改一次)。
我在使用 Java 地图时遇到了一些困难。 我想要一个以 byte[] 作为键和 returns 自定义对象作为值的映射。
首先我尝试使用哈希映射,但因为我习惯于使用不同的数组,但具有相同的值,所以它不起作用。同样使用 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)
当我尝试添加对象时抛出异常。
有人知道如何解决这个异常吗? 或者更具体地说,我应该如何以及向 TreeMap 提供哪个比较器?
好的,这里介绍 material 到 Java。
有两件事在起作用:
- 数组是基于身份的,而不是基于值的(有关更多详细信息,请参阅 this answer;不过,我找不到任何正式的规范)。
因此,以下returns false
:
byte[] a = {1};
byte[] b = {1};
System.out.println(a.equals(b));
- 数组未实现
Comparable
(it would make no sense for them). In order to put anything into aTreeMap
, you must either provide aComparator
for it (using this constructor), or it must implementComparable
。
编辑:如果你确实有一些二进制数据想用作键(这是一个相当奇怪的情况),你可以:
使用 Java NIO 的
ByteBuffer
and itsByteBuffer.wrap(byte[])
方法(缺点:此 class 是可变的,但在您的原始版本中byte[]
也是可变的)。在
byte[]
上创建自定义(最好是不可变的)包装器,并将此 class 用作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);
}
}
原因是您的密钥没有实现Comparable
。
一个解决方案是创建一个 class(包装器)用作密钥:
class ByteArrayKey implements Comparable{
byte[] value;
...
}
您所要做的就是根据需要实施 compareTo(T o )
(检查 Arrays
),当然还要正确使用此实例。
这背后的优点是您不必在每个 TreeMap
中设置一个 Comparator
,您将使用构造函数实例化:
public TreeMap(Comparator<? super K> comparator)
提供更加简洁和可维护的代码(如果等式发生变化,您只需更改一次)。