2016-12-14 10 views
0

В настоящее время я работаю над играми TD с редактором карт. Теперь, очевидно, вы можете сохранять и загружать эти карты (или должны быть способны, по крайней мере). Проблема: в какой-то момент я звоню .get() на HashMap. К сожалению, ключи, которые должны быть одинаковыми (по логике), не являются одним и тем же объектом (в терминах ссылок), и, согласно моим предыдущим исследованиям Google, переопределение их метода .equals недостаточно, поскольку они все еще возвращают разные хэши с .hashCode() (я подтвердил, что они возвращают разные хеши, а .equals действительно возвращает true).
(На стороне записки, это довольно странно, так как Javadoc из HashMap.get(key) только утверждает, что они должны быть равны)HashMap.get() не возвращает правильное значение, благодаря «hashCode()»

Более конкретно, HashMap содержит экземпляры класса Path шахты в качестве ключей, и должен вернуть соответствующий список врагов (= значение).

короткая версия Path (без добытчиков и т.д.):

public class Path 
{ 
    private List<Tile> tiles = new ArrayList<>(); 
    @Override 
    public boolean equals(Object obj) { 
     //code comparing the two paths 
    } 
    @Override 
    public int hashCode() { 
     //what I still need to implement. ATM, it returns super.hashCode() 
    } 
} 

public class Tile 
{ 
    private int x; 
    private int y; 
    //constructor 
    //overrides equals 
    //getters & some convenience methods 
} 

Теперь, если два пути равны, я бы хотел, чтобы вернуть тот же хэш-код, так что HashMap возвращает правильный список враги. (Я буду уверен, что не могут быть добавлены два одинаковых пути).

Теперь мой вопрос:

ли вы предложить

  1. используя некоторую внешнюю библиотеку для генерации хэша-
  2. , что я пишу свою собственную реализацию вычисления хэша или
  3. что-то другое

?

Обратите внимание, что я бы предпочел не менять HashMap на другой тип карты, если это даже поможет решить проблему.

+1

ваш '3)' возможно, возможно, использует вашу IDE или IDE в качестве генератора для генерации 'hashcode' – SomeJavaGuy

+1

, вы можете сделать свой хэш-код простым или сложным, как вам нравится. это означает, что «эти две смутно симлярные» проверки позволяют устранить как можно больше дико отличающихся совпадений до того, как вы погрузитесь в свой метод «равно» для тех, кто выживает при проверке хэш-кода. Таким образом, в зависимости от вашей системы 'return tiles.size()' может быть даже уместным! –

+2

стоит добавить: одна ошибка, сделанная людьми, заключается в том, чтобы сделать hashcode чрезмерно сложным. нет смысла иметь это, если это будет просто сложнее, чем фактический метод 'equals'. как я сказал: это означает «быстрая проверка». –

ответ

1

List имеет полезный метод, который также удобно назвать list.hashCode(). Это вычислит хэш-код всех элементов внутри списка. Таким образом, вы также должны реализовать hashCode для Tile, который, вероятно, состоит из некоторых примитивных полей или таких.

например.

@Override 
    public int hashCode() { 
     return tiles != null ? tiles.hashCode() : 0; 
    } 

См Документах here

INT Hashcode()
Возвращает значение хэш-кода для этого списка. Хэш-код списка определяется как результат следующего расчета:

int hashCode = 1; 
    for (E e : list) 
     hashCode = 31*hashCode + (e==null ? 0 : e.hashCode()); 

Это гарантирует, что list1.equals(list2) означает, что list1.hashCode()==list2.hashCode() для любых двух списков, list1 и list2, в соответствии с требованиями общего договора от Object.hashCode().

+0

'Tile' на самом деле довольно примитивен, он просто сохраняет 2 целых значения (как видно выше). Спасибо за отзыв о list.hashCode()! – PixelMaster

+0

Ваш первый блок кода можно сократить до [Objects.hashCode (плитки)] (http://docs.oracle.com/javase/8/docs/api/java/util/Objects.html#hashCode-java.lang .Object-). – VGR

2

Вам определенно необходимо реализовать свой hashCode, соответствующий equals. IDE часто делают приличную работу hashCode и equals. Также рассмотрите Objects.equals(...) и Objects.hash(...).

Одно предупреждение об использовании Path как ключи в HashMap. Вам нужно будет сделать класс неизменным, чтобы он работал надежно. Или, по крайней мере, убедитесь, что hashCode ключа не изменяется. В противном случае вы не сможете вернуть данные даже с тем же или равным ключом.

+0

относительно неизменности «Пути»: я надеюсь, что мне это не понадобится, так как обычно я буду называть '.get' с помощью пути, полученного через ссылку. Эта ошибка возникает только после загрузки ранее созданной карты. – PixelMaster

+1

@ Misteradi1 Если хэш-код изменения пути, вы не сможете извлекать данные с карты хэша даже с * одним и тем же * экземпляром ключа. Карта хэша снова получит хэш-код ключа и будет использовать его для поиска ведра со значением. Если хеш-код изменяется, он не найдет нужное ведро. Даже если ключ является тем же самым экземпляром. Осторожнее. – lexicore