Java 字节数组集

问题描述 投票:0回答:6

我有一个

byte[]
的哈希集,我想测试该集合中是否有新的
byte[]
。 问题在于,Java 似乎是在测试
byte[]
实例是否相同,而不是测试字节数组中的实际值是否相同。

换句话说,请考虑以下代码:

public class Test
{
    public static void main(String[] args)
    {
        java.util.HashSet<byte[]> set=new java.util.HashSet<byte[]>();
        set.add(new String("abc").getBytes());
        System.out.println(set.contains(new String("abc").getBytes()));
    }
}

此代码打印出

false
,我希望它打印出
true
。 我该怎么做呢?

java set
6个回答
7
投票

您可以使用

ByteBuffer.wrap
包装每个字节数组,这将为您提供正确的 equals 和 hashCode 行为。请小心您在
ByteBuffer
上调用的方法(不要修改数组或推进其指针)。


2
投票

您可以创建一个

ByteArray
类来包装字节数组并按照您想要的方式测试相等性。 然后你就会有一个
Set<ByteArray>


1
投票

您可以定义自己的包装类,但可能最简单的方法是将数组“包装”到 ArrayList 中并使用

HashSet<ArrayList>


1
投票

现代(截至目前的解决方案)

import com.google.common.collect.ImmutableSet;

import java.nio.ByteBuffer;
import java.util.Set;

import static com.google.common.base.Charsets.UTF_8;
import static java.nio.ByteBuffer.wrap;

public class Scratch
{
    public static void main(String[] args)
    {
        final Set<ByteBuffer> bbs = ImmutableSet.of(wrap("abc".getBytes(UTF_8)).asReadOnlyBuffer());
        System.out.println("bbs.contains(ByteBuffer.wrap(\"abc\".getBytes(Charsets.UTF_8))) = " + bbs.contains(wrap("abc".getBytes(UTF_8)).asReadOnlyBuffer()));
    }
}

注意事项:

您应该永远不要

String
转换为
byte[]
而不提供
Charset
,结果会根据默认值
Charset
变得依赖于运行时,这通常不是一个好的结果并且可以更改。

.asReadOnlyBuffer()
很重要!

创建一个新的只读字节缓冲区,共享该缓冲区的 内容。新缓冲区的内容将是该缓冲区的内容。 对此缓冲区内容的更改将在新缓冲区中可见; 然而,新缓冲区本身将是只读的,并且不允许 需要修改的共享内容。

两个缓冲区的位置、限制和标记值将是独立的。

新缓冲区的容量、限制、位置和标记值将与该缓冲区的容量、限制、位置和标记值相同。 如果此缓冲区本身是只读的,则此方法的行为完全相同 与复制方法相同。


0
投票

你可以避免包装器和愚蠢的 hashCode 问题(嘿,像 byte[] 这样的标准东西没有 hashCode 对吧?):

使用TreeSet代替HashSet,并在实例化时提供byte[]比较器:

  Set<byte[]> byteATreeSet = new TreeSet<byte[]>(new Comparator<byte[]>() {
    public int compare(byte[] left, byte[] right) {
    for (int i = 0, j = 0; i < left.length && j < right.length; i++, j++) {
        int a = (left[i] & 0xff);
        int b = (right[j] & 0xff);
        if (a != b) {
            return a - b;
        }
    }
    return left.length - right.length;
   }});

如果你从其他地方得到一个 byte[] HashSet b,请先将你的变量 a 初始化为 TreeSet,然后使用 a.addAll(b);这样,即使 b 包含重复项,a 也不会。


0
投票

实现 Adam Crume 的想法。

public class ByteArraySet
{
    Set<BaWrapper> bws;

    public ByteArraySet()
    {
        bws = new HashSet<BaWrapper>();
    }

    public boolean contains(final byte[] a)
    {
        return bws.contains(new BaWrapper(a));
    }

    public boolean add(final byte[] a)
    {
        return bws.add(new BaWrapper(a));
    }

    public boolean remove(final byte[] a)
    {
        return bws.remove(new BaWrapper(a));
    }

    public  int size()
    {
        return bws.size();
    }

    private static class BaWrapper
    {
        byte[] a;

        BaWrapper(final byte[] a)
        {
            this.a = a;
        }

        @Override
        public boolean equals(final Object rhs)
        {
            return Arrays.equals(a, ((BaWrapper) rhs).a);
        }

        @Override
        public int hashCode()
        {
            return Arrays.hashCode(a);
        }
    }
}
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.