2013-10-01 3 views
0
public static void main(String args[]) throws Exception { 
    ConcurrentHashMap<byte[], Integer> dps = 
     new ConcurrentHashMap<byte[], Integer>(); 

    System.out.println(dps.putIfAbsent("hi".getBytes(), 1)); 
    System.out.println(dps.putIfAbsent("hi".getBytes(), 1)); 
} 

печатаетputIfAbsent() не работает с ConcurrentHashMap

null 
null 

Почему не напечатать 1 на второй линии? Я прочитал семантику для putIfAbsent, и она должна быть гарантирована для работы. (Примечание: это была дистиллированная вниз с большой параллельной программы ... как вы можете видеть, что теперь однопоточных.)

ответ

5

putIfAbsent() не работает с ConcurrentHashMap

"hi".getBytes() не так что вы создаете два разных объекта. Если вы сделали что-то вроде следующего, вы увидите свой 1.

byte[] bytes = "hi".getBytes(); 
System.out.println(dps.putIfAbsent(bytes, 1)); 
System.out.println(dps.putIfAbsent(bytes, 1)); 

В hashCode() и equals(...) методы на byte[] массиве из Object, который смотрит только на ссылки объекта, а не его содержимое.

Всякий раз, когда вы храните что-то в Map, вам необходимо убедиться, что он переопределяет методы hashCode() и equals(...), если вы не хотите просто сравнивать ссылки. Это FAQ по Java. См. Следующие документы: Java theory and practice: Hashing it out.

Как @Mauren упоминает в комментариях, чтобы использовать содержимое из byte[] вы собираетесь иметь, чтобы написать небольшой класс, который облегает byte[] и обеспечивает надлежащие hashCode() и equals(...) методы. Или как @CostiCiudatu упоминает, вы можете использовать SortedMap и использовать Comparator для byte[], который смотрит на содержимое массива.

Как и в сторону, если String.getBytes() возвращает new byte[] закодированный с StringCoding.StringEncoder класса на основе вашего набора символов, и т.д ..

+1

Просто заметил, если я изменю 'байт []' в 'String' (и удалить' GetBytes () 'конечно), то я получаю ожидаемое поведение. Но мои 'String' - разные объекты, поэтому по вашей логике это не должно работать. Или я не понимаю? – Fixee

+0

Хорошо, основываясь на ваших новых изменениях, я понимаю: 'String' сравнивает содержимое, но' byte [] 'сравнивает ссылки. Очень неинтуитивный. Похоже, что использование 'byte []' в качестве ключа карты, как правило, является плохой идеей. – Fixee

+1

@Fixee 'String' имеет переопределенные' equals() 'и' hashCode() 'методы, поэтому он корректно работает с' String'. – Jesper

Смежные вопросы