Метод Hashmap get и containskey не может получить объект, несмотря на то, что реализовал методы equals и hashcode - PullRequest
0 голосов
/ 20 января 2020

У меня есть класс с именем Language, в языке есть несколько полей, но я хочу использовать только одно поле, чтобы иметь возможность сравнивать его с другими объектами языка. Это поле называется languageCode и является строкой. Я автоматически реализовал equals и hashcode, используя инструмент генерации методов Intellij Idea. Вот класс с соответствующим полем и сгенерированными методами.

public class Language implements Serializable{

    private String languageCode

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Language language = (Language) o;
        return languageCode.equals(language.getLanguageCode());
    }

    @Override
    public int hashCode() {
        return Objects.hash(languageCode);
    }

}

Существует также другой класс с именем Journal Журнал также имеет несколько различных полей, но релевантно только одно, а именно:

public class Journal {

  private Map<Language, String> titleTranslations = new HashMap<>()

}

Во всей программе я использую постоянную переменную ENGLISH_LANGUAGE, которая содержит engli sh, представляющий объект языка из базы данных. Все языковые объекты в titleTranslations также взяты из одной таблицы базы данных. Кроме того, журнал определенно имеет объект языка engli sh в своем заголовке Hashmap titleTranslations.

Однако, когда я запускаю следующий тест:

journal.getTitleTranslations().forEach((Language language, String string) ->{
    log.info(language.getLanguageCode() + " " + string);
    log.info("hashcode is " + language.hashCode());
});
log.info("default language " + ENGLISH_LANGUAGE.getLanguageCode());
log.info("hashcode is " + ENGLISH_LANGUAGE.hashCode());
log.info("contains key " + journal.getTitleTranslations().containsKey(ENGLISH_LANGUAGE));
log.info("key is not null " + (journal.getTitleTranslations().get(ENGLISH_LANGUAGE) != null));

Это дает следующий вывод:

de deutsch 
hashcode is 3232 
en english 
hashcode is 3272 
fr francais 
hashcode is 3307 
nl nederlands 
hashcode is 3549 
defautl language en 
hashcode is 3272 
contiains key false 
key is not null false

, и вы можете видеть это, несмотря на хэш-коды ENGLISH_LANGUAGE и engli sh объект языка в переводах заголовков точно такой же (3272), он все еще не может найти ключ при использовании метода get и возвращает false, когда я использую containsKey и использую ENGLISH_LANGUAGE в качестве аргумента.

Может кто-нибудь сказать мне, что я делаю не так? Разве реализации хэш-кода в одном поле не работают?

Спасибо

1 Ответ

1 голос
/ 20 января 2020

Хорошо, проблема связана со структурой. Поскольку я использую фреймворк, использующий прокси-подклассы, такие как Hibernate, метод equals должен быть немного изменен Это то, что intellij может сделать для вас автоматически, когда вы отметите опцию Accept subclasses as parameter to equals() method Ниже этого флажка приведено следующее объяснение:

В то время как, как правило, несовместимость с определением Object.equals (), принимающим подклассы, может быть необходима для сгенерированного метод для корректной работы с каркасами, которые генерируют прокси-подклассы, такие как Hibernate

. Если установить этот флажок, будет создан метод equals, который использует этот оператор if if (!(o instanceof Language)) return false; вместо этого if (o == null || getClass() != o.getClass()) return false;.

Это как-то решает проблему. Метод хеш-кода остается прежним. Вот полный код:

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (!(o instanceof Language)) return false;
    Language language = (Language) o;
    return getLanguageCode().equals(language.getLanguageCode());
}

@Override
public int hashCode() {
    return Objects.hash(getLanguageCode());
}
...