代码之家  ›  专栏  ›  技术社区  ›  Jack Edmonds

字节数组的Java集合

  •  8
  • Jack Edmonds  · 技术社区  · 14 年前

    我有一套 byte[] S和我想测试一下 字节[] 就在那一套。问题在于Java似乎正在测试是否 字节[] 实例是相同的,而不是测试字节数组中的实际值是否相同。

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

    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 . 我该怎么做呢?

    5 回复  |  直到 9 年前
        1
  •  7
  •   Kevin Bourrillion Gergely    14 年前

    您可以使用 ByteBuffer.wrap ,它将为您提供正确的equals和hashcode行为。只是要小心你调用的方法 ByteBuffer (即不修改数组或前进其指针)。

        2
  •  2
  •   Adam Crume    14 年前

    你可以创建一个 ByteArray 类,该类按所需方式包装字节数组和相等性测试。那你就有了 Set<ByteArray> .

        3
  •  1
  •   President James K. Polk    14 年前

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

        4
  •  1
  •   ib84    13 年前

    您可以避免包装器和愚蠢的哈希代码问题(嘿,像byte[]这样的标准事物没有正确的哈希代码?):

    使用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也不会。

        5
  •  1
  •   user177800    9 年前

    现代(目前的解决方案)

    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 到A byte[] 不提供 Charset 根据默认值,结果将依赖于运行时 字符集 这通常不是一个好的,可以改变。

    .asReadOnlyBuffer() 很重要!

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

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

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