Любой недостаток использования произвольных объектов в качестве ключей карты в Java? - PullRequest
6 голосов
/ 11 марта 2009

В моем приложении есть два вида объектов, где каждый объект одного вида имеет ровно один соответствующий объект другого типа.

Очевидный выбор для отслеживания этих отношений - Map<type1, type2>, как в HashMap. Но почему-то я с подозрением. Могу ли я использовать объект в качестве ключа на карте, передать его, поместить его в другую коллекцию и в любое время получить своего партнера с карты?

После создания объекта все, что я передаю, это идентификатор, верно? Так что, вероятно, нет проблем там. Что если я сериализую и десериализую ключ?

Любые другие предостережения? Должен ли я использовать что-то еще для сопоставления пар объектов, например, число, которое я генерирую сам?

Ответы [ 8 ]

22 голосов
/ 11 марта 2009
  1. Ключ должен правильно реализовать .equals() и .hashCode()
  2. Ключ нельзя изменять любым способом, который изменяет его значение .hashCode(), пока он используется в качестве ключа
  3. В идеале любой объект, используемый в качестве ключа в HashMap, должен быть неизменным. Это автоматически гарантирует, что 2. всегда сохраняется.
  4. Объекты, которые в противном случае могли бы быть GCed, могут храниться, когда они используются в качестве ключа и / или значения.
7 голосов
/ 11 марта 2009

У меня есть два вида объектов в моем приложение, где каждый объект одного вид имеет ровно один соответствующий объект другого вида.

Это действительно звучит как отношение has-a и поэтому может быть реализовано с использованием простого атрибута.

3 голосов
/ 11 марта 2009

Зависит от выбранной вами реализации карты:

  • HashMap использует равно () и hashCode () . По умолчанию (в объекте) они основаны на идентичности объекта, которая будет работать нормально, если вы не сериализуете / десериализуете. При правильной реализации equals () и hashCode () в зависимости от содержимого объекта у вас не возникнет проблем, если вы не измените его, пока он является ключом в хэш-карте.

  • TreeMap использует compareTo () . Реализация по умолчанию отсутствует, поэтому вам нужно предоставить ее. Применяются те же ограничения, что и для реализации hashCode () и equals () выше.

1 голос
/ 11 марта 2009

Могу ли я использовать объект в качестве ключа на Карте, передать его, поместить его в другую коллекцию и в любое время получить своего партнера с Карты?

Да, здесь вообще нет проблем.

После создания объекта все, что я передаю, это идентификатор, верно? Так что, вероятно, нет проблем там. Что если я сериализую и десериализую ключ?

Правильно, вы только передаете ссылку - все они будут указывать на один и тот же реальный объект. Если вы сериализуете или десериализуете объект, это создаст новый объект. Однако, если ваш объект правильно реализует функции equals и hashCode, вы все равно сможете использовать новый десериализованный объект для получения элементов с карты.

Любые другие предостережения? Должен ли я использовать что-то еще для сопоставления пар объектов, например число, которое я генерирую сам?

Что касается предупреждений, да, вы не можете изменить ничего, что могло бы вызвать изменение хэш-кода объекта, пока объект находится на карте.

1 голос
/ 11 марта 2009

Вы можете использовать стандартную карту, но при этом вы будете сохранять сильные ссылки на ваши объекты на карте. Если на ваши объекты ссылаются в другой структуре и вам нужна карта, чтобы просто связать их вместе, рассмотрите возможность использования WeakHashMap.

И кстати, вам не нужно переопределять equals и hashCode, если вам не нужно рассматривать несколько экземпляров объекта как равных ...

0 голосов
/ 11 марта 2009

Вы можете рассмотреть коллекцию Google BiMap .

0 голосов
/ 11 марта 2009

Точками сбоя являются хэш-код и функции равенства. Если они не дают последовательных и правильных возвращаемых значений, карта будет вести себя странно. Эффективная Java имеет целый раздел и настоятельно рекомендуется.

0 голосов
/ 11 марта 2009

Любой объект может быть ключом карты. Здесь важно убедиться, что вы переопределяете .equals () и .hashCode () для любых объектов, которые будут использоваться в качестве ключей карты.

Причина, по которой вы делаете это, заключается в том, что если вы этого не сделаете, equals будет пониматься как равенство объектов, и единственный способ найти "равные" ключи карты - это иметь дескриптор самого исходного объекта .

Вы переопределяете хеш-код, потому что он должен быть согласован с equals. Это делается для того, чтобы объекты, которые вы определили как равные хешу, одинаково.

...