【问题标题】:Java set of byte arraysJava 字节数组集
【发布时间】:2010-06-29 02:07:51
【问题描述】:

我有一个 byte[]s 的 HashSet,我想测试一个新的 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


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    您可以创建一个 ByteArray 类来包装字节数组并按照您想要的方式测试相等性。然后你会有一个Set&lt;ByteArray&gt;

    【讨论】:

      【解决方案3】:

      您可以定义自己的包装类,但可能最简单的做法是将数组“包装”到 ArrayLists 中并使用HashSet&lt;ArrayList&gt;

      【讨论】:

        【解决方案4】:

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

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

        注意事项:

        您应该从不在不提供Charset 的情况下将String 转换为byte[],结果将依赖于基于默认Charset 的运行时,这通常不是一个好的结果,并且可以改变。

        .asReadOnlyBuffer() 很重要!

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

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

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

        【讨论】:

          【解决方案5】:

          您可以避免包装器和愚蠢的 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 也不会。

          【讨论】:

          • 值得注意的是,TreeSet 对于添加、删除、包含方法的时间复杂度比 HashSet 更差(O(lg n) vs O(1)),这可能是一个重要因素。
          猜你喜欢
          • 1970-01-01
          • 2011-11-06
          • 2011-10-04
          • 1970-01-01
          • 2011-07-02
          • 2013-01-22
          • 2020-11-18
          • 2011-12-29
          • 1970-01-01
          相关资源
          最近更新 更多