Java 使用字节数组作为 Map 键
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1058149/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Using a byte array as Map key
提问by shikhar
Do you see any problem with using a byte array as Map key? I could also do new String(byte[])
and hash by String
but it is more straightforward to use byte[]
.
您认为使用字节数组作为 Map 键有什么问题吗?我也可以做new String(byte[])
和散列,String
但使用更简单byte[]
。
采纳答案by Kathy Van Stone
The problem is that byte[]
uses object identity for equals
and hashCode
, so that
问题是byte[]
对equals
and使用对象标识hashCode
,因此
byte[] b1 = {1, 2, 3}
byte[] b2 = {1, 2, 3}
will not match in a HashMap
. I see three options:
将不匹配HashMap
. 我看到三个选项:
- Wrapping in a
String
, but then you have to be careful about encoding issues (you need to make certain that the byte -> String -> byte gives you the same bytes). - Use
List<Byte>
(can be expensive in memory). - Do your own wrapping class, writing
hashCode
andequals
to use the contents of the byte array.
- 包装在 a 中
String
,但是您必须注意编码问题(您需要确保字节 -> 字符串 -> 字节为您提供相同的字节)。 - 使用
List<Byte>
(在内存中可能很昂贵)。 - 做你自己的包装类,编写
hashCode
和equals
使用字节数组的内容。
回答by Adam Paynter
I believe that arrays in Java do not necessarily implement the hashCode()
and equals(Object)
methods intuitively. That is, two identical byte arrays will not necessarily share the same hash code and they will not necessarily claim to be equal. Without these two traits, your HashMap will behave unexpectedly.
我认为 Java 中的数组不一定直观地实现hashCode()
和equals(Object)
方法。也就是说,两个相同的字节数组不一定共享相同的哈希码,也不一定声称它们相等。如果没有这两个特征,您的 HashMap 将出现意外行为。
Therefore, I recommend againstusing byte[]
as keys in a HashMap.
因此,我建议对使用byte[]
作为一个HashMap键。
回答by Jon Skeet
It's okay so long as you only want reference equality for your key - arrays don't implement "value equality" in the way that you'd probably want. For example:
只要您只希望键的引用相等就可以了 - 数组不会以您可能想要的方式实现“值相等”。例如:
byte[] array1 = new byte[1];
byte[] array2 = new byte[1];
System.out.println(array1.equals(array2));
System.out.println(array1.hashCode());
System.out.println(array2.hashCode());
prints something like:
打印如下内容:
false
1671711
11394033
(The actual numbers are irrelevant; the fact that they're different is important.)
(实际数字无关紧要;它们不同的事实很重要。)
Assuming you actuallywant equality, I suggest you create your own wrapper which contains a byte[]
and implements equality and hash code generation appropriately:
假设您确实想要相等,我建议您创建自己的包装器,其中包含 abyte[]
并适当地实现相等和哈希代码生成:
public final class ByteArrayWrapper
{
private final byte[] data;
public ByteArrayWrapper(byte[] data)
{
if (data == null)
{
throw new NullPointerException();
}
this.data = data;
}
@Override
public boolean equals(Object other)
{
if (!(other instanceof ByteArrayWrapper))
{
return false;
}
return Arrays.equals(data, ((ByteArrayWrapper)other).data);
}
@Override
public int hashCode()
{
return Arrays.hashCode(data);
}
}
Note that if you change the values within the byte array after using the ByteArrayWrapper
, as a key in a HashMap
(etc) you'll have problems looking up the key again... you could take a copy of the data in the ByteArrayWrapper
constructor if you want, but obviously that will be a waste of performance if you know you won'tbe changing the contents of the byte array.
请注意,如果您在使用ByteArrayWrapper
, 作为 a HashMap
(等)中的键后更改字节数组中的值,则再次查找键时会遇到问题……如果需要,您可以在ByteArrayWrapper
构造函数中复制数据,但显然,如果您知道不会更改字节数组的内容,那将浪费性能。
EDIT: As mentioned in the comments, you could also use ByteBuffer
for this (in particular, its ByteBuffer#wrap(byte[])
method). I don't know whether it's really the right thing, given all the extra abilities that ByteBuffer
s have which you don't need, but it's an option.
编辑:如评论中所述,您也可以ByteBuffer
为此使用(特别是它的ByteBuffer#wrap(byte[])
方法)。考虑到ByteBuffer
您不需要的所有额外能力,我不知道这是否真的正确,但这是一种选择。
回答by dfa
I see problems since you should use Arrays.equals and Array.hashCode, in place of default array implementations
我看到了问题,因为你应该使用 Arrays.equals 和 Array.hashCode,代替默认的数组实现
回答by df.
Arrays.toString(bytes)
Arrays.toString(字节)
回答by Artem Oboturov
You could use java.math.BigInteger
. It has a BigInteger(byte[] val)
constructor. It's a reference type, so could be used as a key for hashtable. And .equals()
and .hashCode()
are defined as for respective integer numbers, which means BigInteger has consistent equals semantics as byte[] array.
你可以使用java.math.BigInteger
. 它有一个BigInteger(byte[] val)
构造函数。它是一种引用类型,因此可以用作哈希表的键。和.equals()
和.hashCode()
被定义为用于各个整数,这意味着具有BigInteger的一致平等语义byte []数组。
回答by byte_array
We can use ByteBuffer for this (This is basically the byte[] wrapper with a comparator)
我们可以为此使用 ByteBuffer(这基本上是带有比较器的 byte[] 包装器)
HashMap<ByteBuffer, byte[]> kvs = new HashMap<ByteBuffer, byte[]>();
byte[] k1 = new byte[]{1,2 ,3};
byte[] k2 = new byte[]{1,2 ,3};
byte[] val = new byte[]{12,23,43,4};
kvs.put(ByteBuffer.wrap(k1), val);
System.out.println(kvs.containsKey(ByteBuffer.wrap(k2)));
will print
将打印
true
回答by Christof R
You could also convert the byte[] to a 'safe' string using Base32 or Base64, for example:
您还可以使用 Base32 或 Base64 将 byte[] 转换为“安全”字符串,例如:
byte[] keyValue = new byte[] {…};
String key = javax.xml.bind.DatatypeConverter.printBase64Binary(keyValue);
of course there are many variants of the above, like:
当然,上面有许多变体,例如:
String key = org.apache.commons.codec.binary.Base64.encodeBase64(keyValue);
回答by Milind Patil
You should use create a class somthing like ByteArrKey and overload hashcode and equal methods, remember the contract between them.
你应该使用创建一个像 ByteArrKey 这样的类并重载 hashcode 和 equal 方法,记住它们之间的契约。
This will give you greater flexibility as you can skip 0 entries that are appended at the end of byte array, specially if you copy only some part form the other byte buffer.
这将为您提供更大的灵活性,因为您可以跳过附加在字节数组末尾的 0 个条目,特别是如果您仅从另一个字节缓冲区复制某些部分。
This way you will decide how both objects SHOULD be equal.
通过这种方式,您将决定两个对象应该如何相等。
回答by Thorsten S.
I am very surprised that the answers are not pointing out the most simple alternative.
我很惊讶答案没有指出最简单的选择。
Yes, it is not possible to use a HashMap, but nobody prevents you from using a SortedMap as alternative. The only thing is to write a Comparator which needs to compare the arrays. It is not as performant as a HashMap, but if you want a simple alternative, here you go (you can replace SortedMap with Map if you want to hide the implementation):
是的,不可能使用 HashMap,但没有人阻止您使用 SortedMap 作为替代方案。唯一的事情是编写一个需要比较数组的比较器。它的性能不如 HashMap,但是如果您想要一个简单的替代方案,那么您可以使用(如果您想隐藏实现,可以将 SortedMap 替换为 Map):
private SortedMap<int[], String> testMap = new TreeMap<>(new ArrayComparator());
private class ArrayComparator implements Comparator<int[]> {
@Override
public int compare(int[] o1, int[] o2) {
int result = 0;
int maxLength = Math.max(o1.length, o2.length);
for (int index = 0; index < maxLength; index++) {
int o1Value = index < o1.length ? o1[index] : 0;
int o2Value = index < o2.length ? o2[index] : 0;
int cmp = Integer.compare(o1Value, o2Value);
if (cmp != 0) {
result = cmp;
break;
}
}
return result;
}
}
This implementation can be adjusted for other arrays, the only thing you must be aware of is that equal arrays (= equal length with equal members) must return 0 and that you have a determistic order
此实现可以针对其他数组进行调整,您唯一必须注意的是相等的数组(= 相等的长度和相等的成员)必须返回 0 并且您具有确定性顺序