Java HashMap с переопределенными hashCode () и equals () не возвращает данных - PullRequest
6 голосов
/ 24 ноября 2010

В последнее время я работаю с HashMap в Java и столкнулся с некоторыми интересными проблемами. В настоящее время я использую его для хранения объектов ключ / значение с несколькими полями. Для этого я переопределил hashCode () и equals () следующим образом:

public final class TransitionState {

private String mStackSymbol;
private String mTransitionSymbol;
private int mState;

private static final int HASH_SEED = 7;     //Should be prime
private static final int HASH_OFFSET = 31;

//Constructor and getter methods here

public boolean equals(TransitionState other) {

    //Check that we aren't comparing against ourself
    if (this == other) {
        return true;
    }

    //Check that we are not comparing against null
    if (other == null) {
        return false;
    }

    //Check fields match
    if ((mState == other.getState()) &&
        (mTransitionSymbol.equals(other.getTransitionSymbol())) &&
        (mStackSymbol.equals(other.getStackSymbol()))) {

        return true;

    } else {
        return false;

    }
}

public int hashCode() {
    int intHash = HASH_SEED;

    //Sum hash codes for individual fields for final hash code
    intHash = (intHash * HASH_OFFSET) + mState;
    intHash = (intHash * HASH_OFFSET) + (mTransitionSymbol == null ? 0 : mTransitionSymbol.hashCode());
    intHash = (intHash * HASH_OFFSET) + (mStackSymbol == null ? 0 : mStackSymbol.hashCode());

    return intHash;
}
}

Теперь я могу без проблем размещать предметы на карте. Однако их получение - другая история. Всякий раз, когда я пытаюсь получить () из HashMap, возвращается NULL. Я написал некоторый тестовый код для итерации по карте и выведите значения, в которых все запутано, поскольку hashCode () моих ключевых объектов совпадает с тем, что есть в моей карте, и равенство с известным значением возвращает true. Пример вывода следующим образом (см. Четвертый переход снизу таблицы):

Transition Table:
State  Symbol  Stack  Move
--------------------------
1, a, b, (1, pop) with key hashcode 212603 and value hashcode 117943
0, b, a, (0, pop) with key hashcode 211672 and value hashcode 117912
1, b, z, (1, push) with key hashcode 212658 and value hashcode 3459456
0, a, b, (0, pop) with key hashcode 211642 and value hashcode 117912
1, a, z, (0, push) with key hashcode 212627 and value hashcode 3459425
0, a, a, (0, push) with key hashcode 211641 and value hashcode 3459425
0, a, z, (0, push) with key hashcode 211666 and value hashcode 3459425
0, b, z, (1, push) with key hashcode 211697 and value hashcode 3459456
1, b, a, (1, pop) with key hashcode 212633 and value hashcode 117943
1, b, b, (1, push) with key hashcode 212634 and value hashcode 3459456

ababba

Transition from (0, a, z) with hashcode 211666
transition.equals(new TransitionState(0, "a", "z")) = true
HashMap containsKey() = false
Transition not found
false

Как видите, ключ соответствует хеш-кодам записи на карте, но мне говорят, что это не существует. Я попытался отладить в метод hasKap hasKap (), который выполняет get (), который проверяется на NULL. Вхождение в get () показывает, что цикл выполняется только один раз, а затем возвращается NULL.

Итак, это проблема HashMap (скорее всего, нет) или (что более вероятно), что я могу делать неправильно? Заранее благодарю за помощь.

Ответы [ 2 ]

19 голосов
/ 24 ноября 2010

Вы не переопределены equals должным образом ... вам нужно

 public boolean equals(Object other)

В настоящее время вы просто перегружаете это.

По существу, переопределение real может выполнять ту же работу, что и существующее, но с первым тестом:

if (!(other instanceof TransitionState))
{
    return false;
}
TransitionState otherState = (TransitionState) other;
// Now do the rest of the comparison

Обратите внимание, что в этом случае проверка на нулевое значение не требуется, так как она не пройдёт тест instanceof.

В наши дни Java позволяет вам добавить аннотацию, чтобы сообщить компилятору, что вы действительно пытаетесь переопределить родительский метод:

 @Overrides
 public boolean equals(Object other)

Теперь компилятор сообщит вам, сделаете ли вы опечатку в имени или ошибетесь с подписью.

2 голосов
/ 24 ноября 2010

Джон прав.Кроме того, вы должны сделать следующее:

Сделать переменные вашего экземпляра окончательными:

private final String mStackSymbol;
private final String mTransitionSymbol;
private final int mState;

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...