使用字节数组作为映射键

2022-08-31 12:19:53

您认为使用字节数组作为 Map 键有什么问题吗?我也可以做和散列,但它使用起来更直接。new String(byte[])Stringbyte[]


答案 1

只要你只想为你的键使用引用相等性就没关系 - 数组不会以你可能想要的方式实现“值相等”。例如:

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());

打印如下内容:

false
1671711
11394033

(实际数字无关紧要;它们不同的事实很重要。

假设你真的想要平等,我建议你创建自己的包装器,其中包含一个并适当地实现平等和哈希代码生成:byte[]

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);
    }
}

请注意,如果在使用 (etc) 中将 后更改字节数组中的值,则再次查找键时会遇到问题...如果需要,您可以在构造函数中获取数据的副本,但是如果您知道自己不会更改字节数组的内容,显然这会浪费性能。ByteArrayWrapperHashMapByteArrayWrapper

编辑:如注释中所述,您也可以使用它(特别是其ByteBuffer#wrap(byte[])方法)。我不知道这是否真的是正确的事情,因为所有额外的能力都是你不需要的,但这是一种选择。ByteBufferByteBuffer


答案 2

问题是 将对象标识用于 和 ,以便byte[]equalshashCode

byte[] b1 = {1, 2, 3}
byte[] b2 = {1, 2, 3}

在 中将不匹配。我看到三个选项:HashMap

  1. 包装在 中,但随后必须小心编码问题(您需要确保字节 ->字符串 ->字节为您提供相同的字节)。String
  2. 使用(在内存中可能很昂贵)。List<Byte>
  3. 执行自己的包装类,编写和使用字节数组的内容。hashCodeequals