Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/ant/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby-on-rails-4/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用字节数组作为映射键_Java_Hashmap_Bytearray - Fatal编程技术网

Java 使用字节数组作为映射键

Java 使用字节数组作为映射键,java,hashmap,bytearray,Java,Hashmap,Bytearray,您认为使用字节数组作为映射键有什么问题吗?我也可以做新字符串(byte[])和按字符串进行散列,但是使用byte[]更简单,我相信Java中的数组不一定直观地实现hashCode()和equals(Object)方法。也就是说,两个相同的字节数组不一定共享相同的哈希代码,也不一定声称相等。如果没有这两个特性,HashMap的行为将出人意料 因此,我建议不要使用byte[]作为HashMap中的键。只要您只希望键的引用相等,就可以了-数组不会以您可能希望的方式实现“值相等”。例如: byte[]

您认为使用字节数组作为映射键有什么问题吗?我也可以做
新字符串(byte[])
和按
字符串进行散列,但是使用
byte[]
更简单,我相信Java中的数组不一定直观地实现
hashCode()
equals(Object)
方法。也就是说,两个相同的字节数组不一定共享相同的哈希代码,也不一定声称相等。如果没有这两个特性,HashMap的行为将出人意料


因此,我建议不要使用
byte[]
作为HashMap中的键。

只要您只希望键的引用相等,就可以了-数组不会以您可能希望的方式实现“值相等”。例如:

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());
byte[] keyValue = new byte[] {…};
String key = javax.xml.bind.DatatypeConverter.printBase64Binary(keyValue);
打印如下内容:

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

假设您确实想要相等,我建议您创建自己的包装器,其中包含
字节[]
,并适当地实现相等和哈希代码生成:

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);
    }
}
请注意,如果在使用
ByteArrayRapper
作为
HashMap
(等)中的键后更改字节数组中的值,则再次查找该键时会遇到问题。。。如果需要,您可以在
ByteArrayRapper
构造函数中复制数据,但是如果您知道不更改字节数组的内容,那么这显然是对性能的浪费


编辑:如评论中所述,您也可以使用
ByteBuffer
进行编辑(尤其是其方法)。我不知道这是否真的是正确的,因为ByteBuffer具有所有您不需要的额外功能,但这是一个选项。

我看到了问题,因为您应该使用Array.equals和Array.hashCode来代替默认的数组实现。

问题在于
byte[]
将对象标识用于
equals
hashCode
,以便

byte[] b1 = {1, 2, 3}
byte[] b2 = {1, 2, 3}
哈希映射中不匹配。我认为有三种选择:

  • 字符串中包装,但是您必须小心编码问题(您需要确保byte->String->byte为您提供相同的字节)
  • 使用
    列表
    (在内存中可能很昂贵)
  • 编写自己的包装类,编写
    hashCode
    equals
    以使用字节数组的内容

  • Arrays.toString(bytes)

    您可以使用
    java.math.biginger
    。它有一个
    biginger(byte[]val)
    构造函数。它是一个引用类型,因此可以用作哈希表的键。和
    .equals()
    .hashCode()
    分别定义为相应的整数,这意味着BigInteger与byte[]数组具有一致的equals语义。

    我们可以使用ByteBuffer实现这一点(这基本上是带有比较器的byte[]包装器)


    您还可以使用Base32或Base64将字节[]转换为“安全”字符串,例如:

    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());
    
    byte[] keyValue = new byte[] {…};
    String key = javax.xml.bind.DatatypeConverter.printBase64Binary(keyValue);
    
    当然,上面有许多变体,例如:

    String key = org.apache.commons.codec.binary.Base64.encodeBase64(keyValue);
    

    您应该使用创建一个类,比如ByteArrKey和重载hashcode以及equal方法,记住它们之间的约定

    这将为您提供更大的灵活性,因为您可以跳过附加在字节数组末尾的0个条目,特别是当您仅复制另一个字节缓冲区中的某些部分时


    这样你就可以决定两个物体应该如何相等。

    我很惊讶,答案没有指出最简单的选择

    是的,不可能使用HashMap,但是没有人阻止您使用SortedMap作为替代。唯一需要做的就是编写一个比较器来比较数组。它的性能不如HashMap,但是如果您想要一个简单的替代方案,那么就来这里(如果您想隐藏实现,可以用Map替换SortedMap):

    private SortedMap testMap=new TreeMap(new ArrayComparator());
    私有类ArrayComparator实现Comparator{
    @凌驾
    公共整数比较(整数[]o1,整数[]o2){
    int结果=0;
    int maxLength=数学最大值(o1.length,o2.length);
    对于(int index=0;index

    此实现可以针对其他数组进行调整,您必须注意的唯一一点是,equal Array(=具有相等成员的equal length)必须返回0,并且您具有确定顺序

    这里有一个使用TreeMap、Comparator接口和java方法java.util.arrays.equals(byte[],byte[])的解决方案

    注:图中的顺序与此方法无关

    SortedMap<byte[], String> testMap = new TreeMap<>(new ArrayComparator());
    
    static class ArrayComparator implements Comparator<byte[]> {
        @Override
        public int compare(byte[] byteArray1, byte[] byteArray2) {
    
            int result = 0;
    
            boolean areEquals = Arrays.equals(byteArray1, byteArray2);
    
            if (!areEquals) {
                result = -1;
            }
    
            return result;
        }
    }
    
    SortedMap testMap=newtreemap(newarraycomparator());
    静态类ArrayComparator实现比较器{
    @凌驾
    公共整数比较(字节[]byteArray1,字节[]byteArray2){
    int结果=0;
    布尔值areEquals=Arrays.equals(byteArray1,byteArray2);
    如果(!arequals){
    结果=-1;
    }
    返回结果;
    }
    }
    
    此外,我们可以像这样创建自己的自定义字节哈希映射

    ByteHashMap byteMap = new ByteHashMap();
    byteMap.put(keybyteArray,valueByteArray);
    
    下面是完整的实现

    public class ByteHashMap implements Map<byte[], byte[]>, Cloneable,
            Serializable {
    
        private Map<ByteArrayWrapper, byte[]> internalMap = new HashMap<ByteArrayWrapper, byte[]>();
    
        public void clear() {
            internalMap.clear();
        }
    
        public boolean containsKey(Object key) {
            if (key instanceof byte[])
                return internalMap.containsKey(new ByteArrayWrapper((byte[]) key));
            return internalMap.containsKey(key);
        }
    
        public boolean containsValue(Object value) {
            return internalMap.containsValue(value);
        }
    
        public Set<java.util.Map.Entry<byte[], byte[]>> entrySet() {
            Iterator<java.util.Map.Entry<ByteArrayWrapper, byte[]>> iterator = internalMap
                    .entrySet().iterator();
            HashSet<Entry<byte[], byte[]>> hashSet = new HashSet<java.util.Map.Entry<byte[], byte[]>>();
            while (iterator.hasNext()) {
                Entry<ByteArrayWrapper, byte[]> entry = iterator.next();
                hashSet.add(new ByteEntry(entry.getKey().data, entry
                        .getValue()));
            }
            return hashSet;
        }
    
        public byte[] get(Object key) {
            if (key instanceof byte[])
                return internalMap.get(new ByteArrayWrapper((byte[]) key));
            return internalMap.get(key);
        }
    
        public boolean isEmpty() {
            return internalMap.isEmpty();
        }
    
        public Set<byte[]> keySet() {
            Set<byte[]> keySet = new HashSet<byte[]>();
            Iterator<ByteArrayWrapper> iterator = internalMap.keySet().iterator();
            while (iterator.hasNext()) {
                keySet.add(iterator.next().data);
            }
            return keySet;
        }
    
        public byte[] put(byte[] key, byte[] value) {
            return internalMap.put(new ByteArrayWrapper(key), value);
        }
    
        @SuppressWarnings("unchecked")
        public void putAll(Map<? extends byte[], ? extends byte[]> m) {
            Iterator<?> iterator = m.entrySet().iterator();
            while (iterator.hasNext()) {
                Entry<? extends byte[], ? extends byte[]> next = (Entry<? extends byte[], ? extends byte[]>) iterator
                        .next();
                internalMap.put(new ByteArrayWrapper(next.getKey()), next
                        .getValue());
            }
        }
    
        public byte[] remove(Object key) {
            if (key instanceof byte[])
                return internalMap.remove(new ByteArrayWrapper((byte[]) key));
            return internalMap.remove(key);
        }
    
        public int size() {
            return internalMap.size();
        }
    
        public Collection<byte[]> values() {
            return internalMap.values();
        }
    
        private final class ByteArrayWrapper {
            private final byte[] data;
    
            public ByteArrayWrapper(byte[] data) {
                if (data == null) {
                    throw new NullPointerException();
                }
                this.data = data;
            }
    
            public boolean equals(Object other) {
                if (!(other instanceof ByteArrayWrapper)) {
                    return false;
                }
                return Arrays.equals(data, ((ByteArrayWrapper) other).data);
            }
    
            public int hashCode() {
                return Arrays.hashCode(data);
            }
        }
    
        private final class ByteEntry implements Entry<byte[], byte[]> {
            private byte[] value;
            private byte[] key;
    
            public ByteEntry(byte[] key, byte[] value) {
                this.key = key;
                this.value = value;
            }
    
            public byte[] getKey() {
                return this.key;
            }
    
            public byte[] getValue() {
                return this.value;
            }
    
            public byte[] setValue(byte[] value) {
                this.value = value;
                return value;
            }
    
        }
    }
    
    公共类ByteHashMap实现映射,可克隆,
    可序列化{
    私有映射internalMap=newhashmap();
    公共空间清除(){
    internalMap.clear();
    }
    公共布尔containsKey(对象键){
    if(字节[]的键实例)
    返回internalMap.containsKey(新的ByteArrayWrapper((字节[])键));
    返回internalMap.containsKey(键);
    }
    公共布尔包含值(对象值){
    返回internalMap.containsValue(值);
    }
    公共图书馆
    
    public class ByteHashMap implements Map<byte[], byte[]>, Cloneable,
            Serializable {
    
        private Map<ByteArrayWrapper, byte[]> internalMap = new HashMap<ByteArrayWrapper, byte[]>();
    
        public void clear() {
            internalMap.clear();
        }
    
        public boolean containsKey(Object key) {
            if (key instanceof byte[])
                return internalMap.containsKey(new ByteArrayWrapper((byte[]) key));
            return internalMap.containsKey(key);
        }
    
        public boolean containsValue(Object value) {
            return internalMap.containsValue(value);
        }
    
        public Set<java.util.Map.Entry<byte[], byte[]>> entrySet() {
            Iterator<java.util.Map.Entry<ByteArrayWrapper, byte[]>> iterator = internalMap
                    .entrySet().iterator();
            HashSet<Entry<byte[], byte[]>> hashSet = new HashSet<java.util.Map.Entry<byte[], byte[]>>();
            while (iterator.hasNext()) {
                Entry<ByteArrayWrapper, byte[]> entry = iterator.next();
                hashSet.add(new ByteEntry(entry.getKey().data, entry
                        .getValue()));
            }
            return hashSet;
        }
    
        public byte[] get(Object key) {
            if (key instanceof byte[])
                return internalMap.get(new ByteArrayWrapper((byte[]) key));
            return internalMap.get(key);
        }
    
        public boolean isEmpty() {
            return internalMap.isEmpty();
        }
    
        public Set<byte[]> keySet() {
            Set<byte[]> keySet = new HashSet<byte[]>();
            Iterator<ByteArrayWrapper> iterator = internalMap.keySet().iterator();
            while (iterator.hasNext()) {
                keySet.add(iterator.next().data);
            }
            return keySet;
        }
    
        public byte[] put(byte[] key, byte[] value) {
            return internalMap.put(new ByteArrayWrapper(key), value);
        }
    
        @SuppressWarnings("unchecked")
        public void putAll(Map<? extends byte[], ? extends byte[]> m) {
            Iterator<?> iterator = m.entrySet().iterator();
            while (iterator.hasNext()) {
                Entry<? extends byte[], ? extends byte[]> next = (Entry<? extends byte[], ? extends byte[]>) iterator
                        .next();
                internalMap.put(new ByteArrayWrapper(next.getKey()), next
                        .getValue());
            }
        }
    
        public byte[] remove(Object key) {
            if (key instanceof byte[])
                return internalMap.remove(new ByteArrayWrapper((byte[]) key));
            return internalMap.remove(key);
        }
    
        public int size() {
            return internalMap.size();
        }
    
        public Collection<byte[]> values() {
            return internalMap.values();
        }
    
        private final class ByteArrayWrapper {
            private final byte[] data;
    
            public ByteArrayWrapper(byte[] data) {
                if (data == null) {
                    throw new NullPointerException();
                }
                this.data = data;
            }
    
            public boolean equals(Object other) {
                if (!(other instanceof ByteArrayWrapper)) {
                    return false;
                }
                return Arrays.equals(data, ((ByteArrayWrapper) other).data);
            }
    
            public int hashCode() {
                return Arrays.hashCode(data);
            }
        }
    
        private final class ByteEntry implements Entry<byte[], byte[]> {
            private byte[] value;
            private byte[] key;
    
            public ByteEntry(byte[] key, byte[] value) {
                this.key = key;
                this.value = value;
            }
    
            public byte[] getKey() {
                return this.key;
            }
    
            public byte[] getValue() {
                return this.value;
            }
    
            public byte[] setValue(byte[] value) {
                this.value = value;
                return value;
            }
    
        }
    }