-1

Here is code block I use in Xamarin Android.

Java.Util.Concurrent.ConcurrentHashMap map = new Java.Util.Concurrent.ConcurrentHashMap();
var key = new byte[] { 1, 2, 3 };
var data = new byte[] { 1, 2, 3, 4, 5 };

map.Put(key, data);
var val = map.Get(key); // null, WHY?

IEnumeration keys = map.Keys();
while (keys.HasMoreElements)
{
    var k = keys.NextElement();
    var val2 = map.Get(k); // NOT null, val2 is byte array of {1,2,3,4,5}
}

I expected val is byte array (data), but val is null, while val2 is not null.

But this Java code works very well.

java.util.concurrent.ConcurrentHashMap map = new java.util.concurrent.ConcurrentHashMap();

byte[] key = {1, 2, 3};
byte[] data = {1, 2, 3, 4, 5};

map.put(key, data);
Object o = map.get(key); // byte array of {1,2,3,4,5}

What is the reason?

Luis
  • 23
  • 7

2 Answers2

1

Using a byte array as a key to a Java map is a really bad idea for a few reasons: arrays are mutable, and arrays don't have reference equality. Both of these things break the general contract of Map. I suggest that you use a different key for the map. See this question and its answers for more information, including some possible ways to convert a byte array into a map key that will work.

Sean Reilly
  • 21,526
  • 4
  • 48
  • 62
  • Dear, @sean-reilly, I know it's bad idea though, but it is from some API of company, anyway I am finding the reason of the issue, instead of avoiding of using array as a key. – Luis Apr 24 '18 at 19:26
1

So long as you only want reference equality for your key - arrays don't implement "value equality" in the way that you'd probably want, But List does. For example:

   byte[] key = new byte[] { 1, 2, 3 };
            byte[] data = new byte[] { 1, 2, 3 };
            System.out.println(key.equals(data));
            System.out.println(key.hashCode());
            System.out.println(data.hashCode());

This will give a output :

false
1829164700
2018699554

Example 2 ::

int[] key = new int[] { 1, 2, 3 };
        int[] data = new int[] { 1, 2, 3 };
        List<Integer> list1 = Arrays.asList(1, 2);
        List<Integer> list2 = Arrays.asList(1, 2);

        System.out.println("Comparison between LIST ::" + list1.equals(list2));
        System.out.println("Comparison between arrays ::" + key.equals(data));
        System.out.println(key.hashCode());
        System.out.println(data.hashCode());

The output is ::

Comparison between LIST ::true
Comparison between arrays ::false
1829164700
2018699554

The problem is that byte[] uses object identity for equals and hashCode, so that will not match in a HashMap.

You can use the given options :

  1. Use List<Byte> (can be expensive in memory).
  2. Do your own wrapping class, writing hashCode and equals to use the contents of the byte array.
  • please check code carefully, I wonder why you compare key and data. No need to compare them. Just put(key, data), and used get(key). – Luis Apr 24 '18 at 19:38
  • I have modified the answer for more details.. I just want to explain that in a Hashmap Arrays wont hold the equality in the way we are expecting it to react.. That is why I compared the key and data.. while in the same case with List, It holds the equality contract – ISHAN KUMAR GHOSH Apr 24 '18 at 19:50
  • See when you are using an object instance as a Hashmap key then You need to implement hashCode and equals on Key. The default implementation of these methods simply checks for instance equality (in other words, two Objects will only be equal if they are in fact the same object). – ISHAN KUMAR GHOSH Apr 24 '18 at 20:23
  • So for arrays the equals contract doesn't holds good.. while for List it works fine.. That is why you should not use Array objects as the Hashmap key – ISHAN KUMAR GHOSH Apr 24 '18 at 20:25
  • https://stackoverflow.com/questions/1058149/using-a-byte-array-as-map-key Check this post – ISHAN KUMAR GHOSH Apr 24 '18 at 20:26
  • Hello, @ishan-kumar-ghosh, don't you check others answer? the link you described is in sean-reilly's answer already. – Luis Apr 25 '18 at 00:31