Мутируемые структуры данных, такие как массивы, противопоказаны для использования в тех местах, где используется хеш-код. Это связано с тем, что структура данных может меняться, тем самым изменяя хэш-код данных, тем самым делая доступ к данным неточным.
Например, предположим, что у меня есть двоичное дерево для хранения элементов на основе их хеш-кода. Если хэш четный, я сохраняю данные с левой стороны, если нечетно с правой стороны. Затем я разделяю хэш на два и повторяю процесс до тех пор, пока хеш не будет равен 0, после чего я буду хранить данные в узле.
Теперь я использую эту структуру в качестве базы для HashSet, а затем храните массив на ней. Массив имеет четный хэш-код, поэтому он идет в левую часть дерева. Давайте проигнорируем его точное положение.
Позже я меняю массив, а затем просматриваю его на множестве. Теперь хеш-код нечетный, и я смотрю на правую сторону дерева и, следовательно, не могу его найти, даже если он хранится в дереве - только на другой стороне.
Итак, не используйте массивы с коллекциями на основе хэшей. Конечно, это не ответит на ваш вопрос.
Что касается вашего вопроса, вам придется подклассировать HashSet, а затем переопределить метод equals. Я не знаю, является ли HashSet окончательным или потомком из запечатанного класса, поэтому я не знаю, является ли это жизнеспособным.
Другим вариантом будет создание альтернативного метода сравнения - без имени равно или "==", основанного исключительно на deepEquals, а затем с помощью метода Pimp My Class, чтобы добавить его в HashSet.
Редактировать
я средний подкласс HashSet, но я не обратил должного внимания на этот вопрос. Я думал, что вы сравниваете весь HashSet, а не просто используете contains. Вы можете сделать это:
class MyHashSet[A] extends scala.collection.mutable.HashSet[A] {
override def contains(elem: A): Boolean = elem match {
case arr : Array[_] => this.elements exists (arr deepEquals _)
case _ => super.contains(elem)
}
}
Это не работает здесь, так как первый случай не соблюдается. Я действительно потерялся здесь, поскольку простые тесты на REPL, похоже, указывают, что он должен работать. Я думаю, что это может иметь какое-то отношение к боксу, но я не совсем понимаю, что - или у меня было бы это работать. :-)
Вы, конечно, правы в отношении опасной комбинации изменяемых структур данных и контейнеров, которые зависят от порядка. Я просто пытался это сделать в прототипе, и мне было интересно, был ли быстрый способ заставить его работать. Кажется, это не так. Я думаю, правильным решением было бы создать класс, который реализует неизменяемый массив байтов с помощью метода equals, который делает то, что мне нужно. –
Btw, снова прочитав ваш ответ, мне интересно, хотите ли вы на самом деле сказать «массив байтов подкласса», поскольку подкласс HashSet не поможет с методом equals (ни Pimp My Class на HashSet не будет). –